kern_physio.c revision 108586
1168404Spjd/* 2168404Spjd * Copyright (c) 1994 John S. Dyson 3168404Spjd * All rights reserved. 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice immediately at the beginning of the file, without modification, 10168404Spjd * this list of conditions, and the following disclaimer. 11168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 12168404Spjd * notice, this list of conditions and the following disclaimer in the 13168404Spjd * documentation and/or other materials provided with the distribution. 14168404Spjd * 3. Absolutely no warranty of function or purpose is made by the author 15168404Spjd * John S. Dyson. 16168404Spjd * 4. Modifications may be freely made to this file if the above conditions 17168404Spjd * are met. 18168404Spjd * 19168404Spjd * $FreeBSD: head/sys/kern/kern_physio.c 108586 2003-01-03 05:57:35Z phk $ 20168404Spjd */ 21236884Smm 22168404Spjd#include <sys/param.h> 23219089Spjd#include <sys/systm.h> 24168404Spjd#include <sys/bio.h> 25168404Spjd#include <sys/buf.h> 26168404Spjd#include <sys/conf.h> 27168404Spjd#include <sys/proc.h> 28236884Smm#include <sys/uio.h> 29236884Smm 30236884Smm#include <vm/vm.h> 31236884Smm#include <vm/vm_extern.h> 32168404Spjd 33168404Spjdstatic void 34168404Spjdphyswakeup(struct buf *bp) 35168404Spjd{ 36168404Spjd wakeup(bp); 37168404Spjd} 38168404Spjd 39168404Spjdint 40168404Spjdphysio(dev_t dev, struct uio *uio, int ioflag) 41168404Spjd{ 42168404Spjd int i; 43168404Spjd int error; 44168404Spjd int spl; 45168404Spjd caddr_t sa; 46168404Spjd u_int iolen; 47168404Spjd struct buf *bp; 48168404Spjd 49168404Spjd /* Keep the process UPAGES from being swapped. XXX: why ? */ 50168404Spjd PHOLD(curproc); 51168404Spjd 52168404Spjd bp = getpbuf(NULL); 53168404Spjd sa = bp->b_data; 54168404Spjd error = bp->b_error = 0; 55168404Spjd 56168404Spjd /* XXX: sanity check */ 57168404Spjd if(dev->si_iosize_max < PAGE_SIZE) { 58168404Spjd printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n", 59168404Spjd devtoname(dev), dev->si_iosize_max); 60168404Spjd dev->si_iosize_max = DFLTPHYS; 61168404Spjd } 62168404Spjd 63168404Spjd for (i = 0; i < uio->uio_iovcnt; i++) { 64168404Spjd while (uio->uio_iov[i].iov_len) { 65168404Spjd bp->b_flags = B_PHYS; 66168404Spjd if (uio->uio_rw == UIO_READ) 67168404Spjd bp->b_iocmd = BIO_READ; 68168404Spjd else 69168404Spjd bp->b_iocmd = BIO_WRITE; 70168404Spjd bp->b_dev = dev; 71168404Spjd bp->b_iodone = physwakeup; 72168404Spjd bp->b_data = uio->uio_iov[i].iov_base; 73168404Spjd bp->b_bcount = uio->uio_iov[i].iov_len; 74168404Spjd bp->b_offset = uio->uio_offset; 75168404Spjd bp->b_saveaddr = sa; 76168404Spjd 77168404Spjd /* Don't exceed drivers iosize limit */ 78168404Spjd if (bp->b_bcount > dev->si_iosize_max) 79168404Spjd bp->b_bcount = dev->si_iosize_max; 80168404Spjd 81168926Spjd /* 82168404Spjd * Make sure the pbuf can map the request 83168926Spjd * XXX: The pbuf has kvasize = MAXPHYS so a request 84168926Spjd * XXX: larger than MAXPHYS - PAGE_SIZE must be 85168404Spjd * XXX: page aligned or it will be fragmented. 86168404Spjd */ 87168404Spjd iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK; 88168404Spjd if ((bp->b_bcount + iolen) > bp->b_kvasize) { 89168404Spjd bp->b_bcount = bp->b_kvasize; 90168404Spjd if (iolen != 0) 91168404Spjd bp->b_bcount -= PAGE_SIZE; 92168404Spjd } 93168404Spjd bp->b_bufsize = bp->b_bcount; 94168404Spjd 95168404Spjd bp->b_blkno = btodb(bp->b_offset); 96168404Spjd 97168404Spjd if (uio->uio_segflg == UIO_USERSPACE) { 98168404Spjd if (!useracc(bp->b_data, bp->b_bufsize, 99168404Spjd bp->b_iocmd == BIO_READ ? 100168404Spjd VM_PROT_WRITE : VM_PROT_READ)) { 101168404Spjd error = EFAULT; 102168404Spjd goto doerror; 103168404Spjd } 104168404Spjd vmapbuf(bp); 105168404Spjd } 106168404Spjd 107168404Spjd DEV_STRATEGY(bp); 108168404Spjd spl = splbio(); 109168404Spjd while ((bp->b_flags & B_DONE) == 0) 110168926Spjd tsleep(bp, PRIBIO, "physstr", 0); 111168404Spjd splx(spl); 112168404Spjd 113168404Spjd if (uio->uio_segflg == UIO_USERSPACE) 114168404Spjd vunmapbuf(bp); 115168404Spjd iolen = bp->b_bcount - bp->b_resid; 116168404Spjd if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR)) 117168404Spjd goto doerror; /* EOF */ 118168404Spjd uio->uio_iov[i].iov_len -= iolen; 119168404Spjd uio->uio_iov[i].iov_base = 120168404Spjd (char *)uio->uio_iov[i].iov_base + iolen; 121168404Spjd uio->uio_resid -= iolen; 122168404Spjd uio->uio_offset += iolen; 123168404Spjd if( bp->b_ioflags & BIO_ERROR) { 124168404Spjd error = bp->b_error; 125168404Spjd goto doerror; 126168404Spjd } 127168404Spjd } 128168404Spjd } 129168404Spjddoerror: 130168404Spjd relpbuf(bp, NULL); 131168404Spjd PRELE(curproc); 132168404Spjd return (error); 133168404Spjd} 134168404Spjd