126f9a767SRodney W. Grimes /* 226f9a767SRodney W. Grimes * Copyright (c) 1994 John S. Dyson 326f9a767SRodney W. Grimes * All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 926f9a767SRodney W. Grimes * notice immediately at the beginning of the file, without modification, 1026f9a767SRodney W. Grimes * this list of conditions, and the following disclaimer. 11df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 12df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 13df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1426f9a767SRodney W. Grimes * 3. Absolutely no warranty of function or purpose is made by the author 1526f9a767SRodney W. Grimes * John S. Dyson. 1626f9a767SRodney W. Grimes * 4. Modifications may be freely made to this file if the above conditions 1726f9a767SRodney W. Grimes * are met. 183c4dd356SDavid Greenman * 19c48d1775SPoul-Henning Kamp * $Id: kern_physio.c,v 1.32 1999/05/06 20:00:25 phk Exp $ 20df8bae1dSRodney W. Grimes */ 21df8bae1dSRodney W. Grimes 22df8bae1dSRodney W. Grimes #include <sys/param.h> 23df8bae1dSRodney W. Grimes #include <sys/systm.h> 24df8bae1dSRodney W. Grimes #include <sys/buf.h> 25df8bae1dSRodney W. Grimes #include <sys/conf.h> 26df8bae1dSRodney W. Grimes #include <sys/proc.h> 2708637435SBruce Evans #include <sys/uio.h> 2808637435SBruce Evans 2926f9a767SRodney W. Grimes #include <vm/vm.h> 30efeaf95aSDavid Greenman #include <vm/vm_extern.h> 31df8bae1dSRodney W. Grimes 3298d93822SBruce Evans static void physwakeup __P((struct buf *bp)); 3350ce7ff4SJohn Dyson static struct buf * phygetvpbuf(dev_t dev, int resid); 3426f9a767SRodney W. Grimes 3526f9a767SRodney W. Grimes int 36c48d1775SPoul-Henning Kamp physread(dev_t dev, struct uio *uio, int ioflag) 37c48d1775SPoul-Henning Kamp { 38c48d1775SPoul-Henning Kamp return(physio(cdevsw[major(dev)]->d_strategy, NULL, dev, 1, minphys, uio)); 39c48d1775SPoul-Henning Kamp } 40c48d1775SPoul-Henning Kamp 41c48d1775SPoul-Henning Kamp int 42c48d1775SPoul-Henning Kamp physwrite(dev_t dev, struct uio *uio, int ioflag) 43c48d1775SPoul-Henning Kamp { 44c48d1775SPoul-Henning Kamp return(physio(cdevsw[major(dev)]->d_strategy, NULL, dev, 0, minphys, uio)); 45c48d1775SPoul-Henning Kamp } 46c48d1775SPoul-Henning Kamp 47c48d1775SPoul-Henning Kamp int 4826f9a767SRodney W. Grimes physio(strategy, bp, dev, rw, minp, uio) 49b5e8ce9fSBruce Evans d_strategy_t *strategy; 5026f9a767SRodney W. Grimes struct buf *bp; 5126f9a767SRodney W. Grimes dev_t dev; 5226f9a767SRodney W. Grimes int rw; 5398d93822SBruce Evans u_int (*minp) __P((struct buf *bp)); 5426f9a767SRodney W. Grimes struct uio *uio; 55df8bae1dSRodney W. Grimes { 5626f9a767SRodney W. Grimes int i; 5726f9a767SRodney W. Grimes int bufflags = rw?B_READ:0; 5826f9a767SRodney W. Grimes int error; 5926f9a767SRodney W. Grimes int spl; 6016f62314SDavid Greenman caddr_t sa; 6116f62314SDavid Greenman int bp_alloc = (bp == 0); 6216f62314SDavid Greenman struct buf *bpa; 63df8bae1dSRodney W. Grimes 64df8bae1dSRodney W. Grimes /* 6557dc5948SPeter Wemm * Keep the process UPAGES from being swapped. (XXX for performance?) 66df8bae1dSRodney W. Grimes */ 6757dc5948SPeter Wemm PHOLD(curproc); 6826f9a767SRodney W. Grimes 6926f9a767SRodney W. Grimes /* create and build a buffer header for a transfer */ 7050ce7ff4SJohn Dyson bpa = (struct buf *)phygetvpbuf(dev, uio->uio_resid); 7116f62314SDavid Greenman if (!bp_alloc) { 7226f9a767SRodney W. Grimes spl = splbio(); 7326f9a767SRodney W. Grimes while (bp->b_flags & B_BUSY) { 7426f9a767SRodney W. Grimes bp->b_flags |= B_WANTED; 7526f9a767SRodney W. Grimes tsleep((caddr_t)bp, PRIBIO, "physbw", 0); 7626f9a767SRodney W. Grimes } 7726f9a767SRodney W. Grimes bp->b_flags |= B_BUSY; 7826f9a767SRodney W. Grimes splx(spl); 7916f62314SDavid Greenman } else { 8016f62314SDavid Greenman bp = bpa; 8126f9a767SRodney W. Grimes } 8226f9a767SRodney W. Grimes 8316f62314SDavid Greenman /* 8416f62314SDavid Greenman * get a copy of the kva from the physical buffer 8516f62314SDavid Greenman */ 8616f62314SDavid Greenman sa = bpa->b_data; 8726f9a767SRodney W. Grimes error = bp->b_error = 0; 8826f9a767SRodney W. Grimes 8926f9a767SRodney W. Grimes for(i=0;i<uio->uio_iovcnt;i++) { 9026f9a767SRodney W. Grimes while( uio->uio_iov[i].iov_len) { 9126f9a767SRodney W. Grimes 9250ce7ff4SJohn Dyson bp->b_dev = dev; 9326f9a767SRodney W. Grimes bp->b_bcount = uio->uio_iov[i].iov_len; 944b83b27fSJohn Dyson bp->b_flags = B_BUSY | B_PHYS | B_CALL | bufflags; 954b83b27fSJohn Dyson bp->b_iodone = physwakeup; 964b83b27fSJohn Dyson bp->b_data = uio->uio_iov[i].iov_base; 97a481f200SDavid Greenman bp->b_bcount = minp( bp); 98a481f200SDavid Greenman if( minp != minphys) 99a481f200SDavid Greenman bp->b_bcount = minphys( bp); 10026f9a767SRodney W. Grimes bp->b_bufsize = bp->b_bcount; 10116f62314SDavid Greenman /* 10216f62314SDavid Greenman * pass in the kva from the physical buffer 10316f62314SDavid Greenman * for the temporary kernel mapping. 10416f62314SDavid Greenman */ 10516f62314SDavid Greenman bp->b_saveaddr = sa; 10626f9a767SRodney W. Grimes bp->b_blkno = btodb(uio->uio_offset); 107e620a1cbSSøren Schmidt bp->b_offset = uio->uio_offset; 10826f9a767SRodney W. Grimes 1096884d2aaSPeter Wemm if (uio->uio_segflg == UIO_USERSPACE) { 11026f9a767SRodney W. Grimes if (rw && !useracc(bp->b_data, bp->b_bufsize, B_WRITE)) { 11126f9a767SRodney W. Grimes error = EFAULT; 11226f9a767SRodney W. Grimes goto doerror; 11326f9a767SRodney W. Grimes } 11426f9a767SRodney W. Grimes if (!rw && !useracc(bp->b_data, bp->b_bufsize, B_READ)) { 11526f9a767SRodney W. Grimes error = EFAULT; 11626f9a767SRodney W. Grimes goto doerror; 11726f9a767SRodney W. Grimes } 11826f9a767SRodney W. Grimes 1196884d2aaSPeter Wemm /* bring buffer into kernel space */ 12026f9a767SRodney W. Grimes vmapbuf(bp); 1216884d2aaSPeter Wemm } 12226f9a767SRodney W. Grimes 12326f9a767SRodney W. Grimes /* perform transfer */ 12426f9a767SRodney W. Grimes (*strategy)(bp); 12526f9a767SRodney W. Grimes 12626f9a767SRodney W. Grimes spl = splbio(); 12726f9a767SRodney W. Grimes while ((bp->b_flags & B_DONE) == 0) 12826f9a767SRodney W. Grimes tsleep((caddr_t)bp, PRIBIO, "physstr", 0); 12926f9a767SRodney W. Grimes splx(spl); 13026f9a767SRodney W. Grimes 1316884d2aaSPeter Wemm /* release mapping into kernel space */ 1326884d2aaSPeter Wemm if (uio->uio_segflg == UIO_USERSPACE) 13326f9a767SRodney W. Grimes vunmapbuf(bp); 13426f9a767SRodney W. Grimes 13526f9a767SRodney W. Grimes /* 13626f9a767SRodney W. Grimes * update the uio data 13726f9a767SRodney W. Grimes */ 13826f9a767SRodney W. Grimes { 13926f9a767SRodney W. Grimes int iolen = bp->b_bcount - bp->b_resid; 1407d7bb69dSDavid Greenman 1417d7bb69dSDavid Greenman if (iolen == 0 && !(bp->b_flags & B_ERROR)) 1427d7bb69dSDavid Greenman goto doerror; /* EOF */ 14326f9a767SRodney W. Grimes uio->uio_iov[i].iov_len -= iolen; 14426f9a767SRodney W. Grimes uio->uio_iov[i].iov_base += iolen; 14526f9a767SRodney W. Grimes uio->uio_resid -= iolen; 14626f9a767SRodney W. Grimes uio->uio_offset += iolen; 14726f9a767SRodney W. Grimes } 14826f9a767SRodney W. Grimes 14926f9a767SRodney W. Grimes /* 15026f9a767SRodney W. Grimes * check for an error 15126f9a767SRodney W. Grimes */ 15226f9a767SRodney W. Grimes if( bp->b_flags & B_ERROR) { 15326f9a767SRodney W. Grimes error = bp->b_error; 15426f9a767SRodney W. Grimes goto doerror; 15526f9a767SRodney W. Grimes } 15626f9a767SRodney W. Grimes } 15726f9a767SRodney W. Grimes } 15826f9a767SRodney W. Grimes 15926f9a767SRodney W. Grimes 16026f9a767SRodney W. Grimes doerror: 1611c7c3c6aSMatthew Dillon relpbuf(bpa, NULL); 16216f62314SDavid Greenman if (!bp_alloc) { 16326f9a767SRodney W. Grimes bp->b_flags &= ~(B_BUSY|B_PHYS); 16426f9a767SRodney W. Grimes if( bp->b_flags & B_WANTED) { 16526f9a767SRodney W. Grimes bp->b_flags &= ~B_WANTED; 16626f9a767SRodney W. Grimes wakeup((caddr_t)bp); 16726f9a767SRodney W. Grimes } 16826f9a767SRodney W. Grimes } 16926f9a767SRodney W. Grimes /* 17057dc5948SPeter Wemm * Allow the process UPAGES to be swapped again. 17126f9a767SRodney W. Grimes */ 17257dc5948SPeter Wemm PRELE(curproc); 17326f9a767SRodney W. Grimes 17426f9a767SRodney W. Grimes return (error); 175df8bae1dSRodney W. Grimes } 176df8bae1dSRodney W. Grimes 177df8bae1dSRodney W. Grimes u_int 178eb776aeaSBruce Evans minphys(bp) 179eb776aeaSBruce Evans struct buf *bp; 180df8bae1dSRodney W. Grimes { 18150ce7ff4SJohn Dyson u_int maxphys = DFLTPHYS; 182f7ea2f55SJulian Elischer struct cdevsw *bdsw; 18350ce7ff4SJohn Dyson 184f7ea2f55SJulian Elischer bdsw = cdevsw[major(bp->b_dev)]; 18550ce7ff4SJohn Dyson 18650ce7ff4SJohn Dyson if (bdsw && bdsw->d_maxio) { 18750ce7ff4SJohn Dyson maxphys = bdsw->d_maxio; 18850ce7ff4SJohn Dyson } 189aec0bcdfSJohn Dyson if (bp->b_kvasize && (bp->b_kvasize < maxphys)) 19050ce7ff4SJohn Dyson maxphys = bp->b_kvasize; 191df8bae1dSRodney W. Grimes 1924b83b27fSJohn Dyson if(((vm_offset_t) bp->b_data) & PAGE_MASK) { 19350ce7ff4SJohn Dyson maxphys -= PAGE_SIZE; 1944b83b27fSJohn Dyson } 1954b83b27fSJohn Dyson 1964b83b27fSJohn Dyson if( bp->b_bcount > maxphys) { 1974b83b27fSJohn Dyson bp->b_bcount = maxphys; 19826f9a767SRodney W. Grimes } 19950ce7ff4SJohn Dyson 20026f9a767SRodney W. Grimes return bp->b_bcount; 201df8bae1dSRodney W. Grimes } 202df8bae1dSRodney W. Grimes 20350ce7ff4SJohn Dyson struct buf * 20450ce7ff4SJohn Dyson phygetvpbuf(dev_t dev, int resid) 20550ce7ff4SJohn Dyson { 206f7ea2f55SJulian Elischer struct cdevsw *bdsw; 20750ce7ff4SJohn Dyson int maxio; 20850ce7ff4SJohn Dyson 209f7ea2f55SJulian Elischer bdsw = cdevsw[major(dev)]; 210f7ea2f55SJulian Elischer if ((bdsw == NULL) || (bdsw->d_bmaj == -1)) 2111c7c3c6aSMatthew Dillon return getpbuf(NULL); 21250ce7ff4SJohn Dyson 21350ce7ff4SJohn Dyson maxio = bdsw->d_maxio; 21450ce7ff4SJohn Dyson if (resid > maxio) 21550ce7ff4SJohn Dyson resid = maxio; 21650ce7ff4SJohn Dyson 2171c7c3c6aSMatthew Dillon return getpbuf(NULL); 21850ce7ff4SJohn Dyson } 21950ce7ff4SJohn Dyson 22026f9a767SRodney W. Grimes static void 22126f9a767SRodney W. Grimes physwakeup(bp) 22226f9a767SRodney W. Grimes struct buf *bp; 22326f9a767SRodney W. Grimes { 22426f9a767SRodney W. Grimes wakeup((caddr_t) bp); 22526f9a767SRodney W. Grimes bp->b_flags &= ~B_CALL; 226df8bae1dSRodney W. Grimes } 227