kern_physio.c revision 254760
1254721Semaste/*- 2254721Semaste * Copyright (c) 1994 John S. Dyson 3254721Semaste * All rights reserved. 4254721Semaste * 5254721Semaste * Redistribution and use in source and binary forms, with or without 6254721Semaste * modification, are permitted provided that the following conditions 7254721Semaste * are met: 8254721Semaste * 1. Redistributions of source code must retain the above copyright 9254721Semaste * notice immediately at the beginning of the file, without modification, 10254721Semaste * this list of conditions, and the following disclaimer. 11254721Semaste * 2. Redistributions in binary form must reproduce the above copyright 12254721Semaste * notice, this list of conditions and the following disclaimer in the 13254721Semaste * documentation and/or other materials provided with the distribution. 14254721Semaste * 3. Absolutely no warranty of function or purpose is made by the author 15254721Semaste * John S. Dyson. 16254721Semaste * 4. Modifications may be freely made to this file if the above conditions 17254721Semaste * are met. 18254721Semaste */ 19254721Semaste 20254721Semaste#include <sys/cdefs.h> 21254721Semaste__FBSDID("$FreeBSD: head/sys/kern/kern_physio.c 254760 2013-08-24 04:52:22Z ken $"); 22254721Semaste 23254721Semaste#include <sys/param.h> 24254721Semaste#include <sys/systm.h> 25254721Semaste#include <sys/bio.h> 26254721Semaste#include <sys/buf.h> 27254721Semaste#include <sys/conf.h> 28254721Semaste#include <sys/proc.h> 29254721Semaste#include <sys/uio.h> 30254721Semaste 31254721Semaste#include <vm/vm.h> 32254721Semaste#include <vm/vm_extern.h> 33254721Semaste 34254721Semasteint 35254721Semastephysio(struct cdev *dev, struct uio *uio, int ioflag) 36254721Semaste{ 37254721Semaste struct buf *bp; 38254721Semaste struct cdevsw *csw; 39254721Semaste caddr_t sa; 40254721Semaste u_int iolen; 41254721Semaste int error, i, mapped; 42254721Semaste 43254721Semaste /* Keep the process UPAGES from being swapped. XXX: why ? */ 44254721Semaste PHOLD(curproc); 45254721Semaste 46254721Semaste bp = getpbuf(NULL); 47254721Semaste sa = bp->b_data; 48254721Semaste error = 0; 49254721Semaste 50254721Semaste /* XXX: sanity check */ 51254721Semaste if(dev->si_iosize_max < PAGE_SIZE) { 52254721Semaste printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n", 53254721Semaste devtoname(dev), dev->si_iosize_max); 54254721Semaste dev->si_iosize_max = DFLTPHYS; 55254721Semaste } 56254721Semaste 57254721Semaste /* 58254721Semaste * If the driver does not want I/O to be split, that means that we 59254721Semaste * need to reject any requests that will not fit into one buffer. 60254721Semaste */ 61254721Semaste if ((dev->si_flags & SI_NOSPLIT) && 62254721Semaste ((uio->uio_resid > dev->si_iosize_max) || 63254721Semaste (uio->uio_resid > MAXPHYS) || 64254721Semaste (uio->uio_iovcnt > 1))) { 65254721Semaste /* 66254721Semaste * Tell the user why his I/O was rejected. 67254721Semaste */ 68254721Semaste if (uio->uio_resid > dev->si_iosize_max) 69254721Semaste printf("%s: request size %zd > si_iosize_max=%d, " 70254721Semaste "cannot split request\n", devtoname(dev), 71254721Semaste uio->uio_resid, dev->si_iosize_max); 72254721Semaste 73254721Semaste if (uio->uio_resid > MAXPHYS) 74254721Semaste printf("%s: request size %zd > MAXPHYS=%d, " 75254721Semaste "cannot split request\n", devtoname(dev), 76254721Semaste uio->uio_resid, MAXPHYS); 77254721Semaste 78254721Semaste if (uio->uio_iovcnt > 1) 79254721Semaste printf("%s: request vectors=%d > 1, " 80254721Semaste "cannot split request\n", devtoname(dev), 81254721Semaste uio->uio_iovcnt); 82254721Semaste 83254721Semaste error = EFBIG; 84254721Semaste goto doerror; 85254721Semaste } 86254721Semaste 87254721Semaste for (i = 0; i < uio->uio_iovcnt; i++) { 88254721Semaste while (uio->uio_iov[i].iov_len) { 89254721Semaste bp->b_flags = 0; 90254721Semaste if (uio->uio_rw == UIO_READ) { 91254721Semaste bp->b_iocmd = BIO_READ; 92254721Semaste curthread->td_ru.ru_inblock++; 93254721Semaste } else { 94254721Semaste bp->b_iocmd = BIO_WRITE; 95254721Semaste curthread->td_ru.ru_oublock++; 96254721Semaste } 97254721Semaste bp->b_iodone = bdone; 98254721Semaste bp->b_data = uio->uio_iov[i].iov_base; 99254721Semaste bp->b_bcount = uio->uio_iov[i].iov_len; 100254721Semaste bp->b_offset = uio->uio_offset; 101254721Semaste bp->b_iooffset = uio->uio_offset; 102254721Semaste bp->b_saveaddr = sa; 103254721Semaste 104254721Semaste /* Don't exceed drivers iosize limit */ 105254721Semaste if (bp->b_bcount > dev->si_iosize_max) 106254721Semaste bp->b_bcount = dev->si_iosize_max; 107254721Semaste 108254721Semaste /* 109254721Semaste * Make sure the pbuf can map the request 110254721Semaste * XXX: The pbuf has kvasize = MAXPHYS so a request 111254721Semaste * XXX: larger than MAXPHYS - PAGE_SIZE must be 112254721Semaste * XXX: page aligned or it will be fragmented. 113254721Semaste */ 114254721Semaste iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK; 115254721Semaste if ((bp->b_bcount + iolen) > bp->b_kvasize) { 116254721Semaste /* 117254721Semaste * This device does not want I/O to be split. 118254721Semaste */ 119254721Semaste if (dev->si_flags & SI_NOSPLIT) { 120254721Semaste printf("%s: request ptr %#jx is not " 121254721Semaste "on a page boundary, cannot split " 122254721Semaste "request\n", devtoname(dev), 123254721Semaste (uintmax_t)bp->b_data); 124254721Semaste error = EFBIG; 125254721Semaste goto doerror; 126254721Semaste } 127254721Semaste bp->b_bcount = bp->b_kvasize; 128254721Semaste if (iolen != 0) 129254721Semaste bp->b_bcount -= PAGE_SIZE; 130254721Semaste } 131254721Semaste bp->b_bufsize = bp->b_bcount; 132254721Semaste 133254721Semaste bp->b_blkno = btodb(bp->b_offset); 134254721Semaste 135254721Semaste csw = dev->si_devsw; 136254721Semaste if (uio->uio_segflg == UIO_USERSPACE) { 137254721Semaste if (dev->si_flags & SI_UNMAPPED) 138254721Semaste mapped = 0; 139254721Semaste else 140254721Semaste mapped = 1; 141254721Semaste if (vmapbuf(bp, mapped) < 0) { 142254721Semaste error = EFAULT; 143254721Semaste goto doerror; 144254721Semaste } 145254721Semaste } 146254721Semaste 147254721Semaste dev_strategy_csw(dev, csw, bp); 148254721Semaste if (uio->uio_rw == UIO_READ) 149254721Semaste bwait(bp, PRIBIO, "physrd"); 150254721Semaste else 151254721Semaste bwait(bp, PRIBIO, "physwr"); 152254721Semaste 153254721Semaste if (uio->uio_segflg == UIO_USERSPACE) 154254721Semaste vunmapbuf(bp); 155254721Semaste iolen = bp->b_bcount - bp->b_resid; 156254721Semaste if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR)) 157254721Semaste goto doerror; /* EOF */ 158254721Semaste uio->uio_iov[i].iov_len -= iolen; 159254721Semaste uio->uio_iov[i].iov_base = 160254721Semaste (char *)uio->uio_iov[i].iov_base + iolen; 161254721Semaste uio->uio_resid -= iolen; 162254721Semaste uio->uio_offset += iolen; 163254721Semaste if( bp->b_ioflags & BIO_ERROR) { 164254721Semaste error = bp->b_error; 165254721Semaste goto doerror; 166254721Semaste } 167254721Semaste } 168254721Semaste } 169254721Semastedoerror: 170254721Semaste relpbuf(bp, NULL); 171254721Semaste PRELE(curproc); 172254721Semaste return (error); 173254721Semaste} 174254721Semaste