19454b2d8SWarner Losh /*- 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. 18df8bae1dSRodney W. Grimes */ 19df8bae1dSRodney W. Grimes 20677b542eSDavid E. O'Brien #include <sys/cdefs.h> 21677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 22677b542eSDavid E. O'Brien 23df8bae1dSRodney W. Grimes #include <sys/param.h> 24df8bae1dSRodney W. Grimes #include <sys/systm.h> 259626b608SPoul-Henning Kamp #include <sys/bio.h> 26df8bae1dSRodney W. Grimes #include <sys/buf.h> 27df8bae1dSRodney W. Grimes #include <sys/conf.h> 28df8bae1dSRodney W. Grimes #include <sys/proc.h> 2908637435SBruce Evans #include <sys/uio.h> 3008637435SBruce Evans 3126f9a767SRodney W. Grimes #include <vm/vm.h> 32efeaf95aSDavid Greenman #include <vm/vm_extern.h> 33df8bae1dSRodney W. Grimes 34c48d1775SPoul-Henning Kamp int 3589c9c53dSPoul-Henning Kamp physio(struct cdev *dev, struct uio *uio, int ioflag) 36df8bae1dSRodney W. Grimes { 37d1e99f43SKonstantin Belousov struct buf *bp; 38d1e99f43SKonstantin Belousov struct cdevsw *csw; 3916f62314SDavid Greenman caddr_t sa; 407179e74fSPoul-Henning Kamp u_int iolen; 41d1e99f43SKonstantin Belousov int error, i, mapped; 42df8bae1dSRodney W. Grimes 437179e74fSPoul-Henning Kamp /* Keep the process UPAGES from being swapped. XXX: why ? */ 4457dc5948SPeter Wemm PHOLD(curproc); 4526f9a767SRodney W. Grimes 467179e74fSPoul-Henning Kamp bp = getpbuf(NULL); 477179e74fSPoul-Henning Kamp sa = bp->b_data; 48ef38cda1SAlan Cox error = 0; 4926f9a767SRodney W. Grimes 507179e74fSPoul-Henning Kamp /* XXX: sanity check */ 517179e74fSPoul-Henning Kamp if(dev->si_iosize_max < PAGE_SIZE) { 527179e74fSPoul-Henning Kamp printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n", 537179e74fSPoul-Henning Kamp devtoname(dev), dev->si_iosize_max); 547179e74fSPoul-Henning Kamp dev->si_iosize_max = DFLTPHYS; 557179e74fSPoul-Henning Kamp } 567179e74fSPoul-Henning Kamp 5793729c17SKenneth D. Merry /* 5893729c17SKenneth D. Merry * If the driver does not want I/O to be split, that means that we 5993729c17SKenneth D. Merry * need to reject any requests that will not fit into one buffer. 6093729c17SKenneth D. Merry */ 61*880e57b6SKenneth D. Merry if (dev->si_flags & SI_NOSPLIT && 62*880e57b6SKenneth D. Merry (uio->uio_resid > dev->si_iosize_max || uio->uio_resid > MAXPHYS || 63*880e57b6SKenneth D. Merry uio->uio_iovcnt > 1)) { 6493729c17SKenneth D. Merry /* 6593729c17SKenneth D. Merry * Tell the user why his I/O was rejected. 6693729c17SKenneth D. Merry */ 6793729c17SKenneth D. Merry if (uio->uio_resid > dev->si_iosize_max) 68*880e57b6SKenneth D. Merry uprintf("%s: request size=%zd > si_iosize_max=%d; " 6993729c17SKenneth D. Merry "cannot split request\n", devtoname(dev), 7093729c17SKenneth D. Merry uio->uio_resid, dev->si_iosize_max); 7193729c17SKenneth D. Merry if (uio->uio_resid > MAXPHYS) 72*880e57b6SKenneth D. Merry uprintf("%s: request size=%zd > MAXPHYS=%d; " 7393729c17SKenneth D. Merry "cannot split request\n", devtoname(dev), 7493729c17SKenneth D. Merry uio->uio_resid, MAXPHYS); 7593729c17SKenneth D. Merry if (uio->uio_iovcnt > 1) 76*880e57b6SKenneth D. Merry uprintf("%s: request vectors=%d > 1; " 7793729c17SKenneth D. Merry "cannot split request\n", devtoname(dev), 7893729c17SKenneth D. Merry uio->uio_iovcnt); 7993729c17SKenneth D. Merry 8093729c17SKenneth D. Merry error = EFBIG; 8193729c17SKenneth D. Merry goto doerror; 8293729c17SKenneth D. Merry } 8393729c17SKenneth D. Merry 8426f9a767SRodney W. Grimes for (i = 0; i < uio->uio_iovcnt; i++) { 8526f9a767SRodney W. Grimes while (uio->uio_iov[i].iov_len) { 8600cbe31bSPoul-Henning Kamp bp->b_flags = 0; 87eea7f71cSKonstantin Belousov if (uio->uio_rw == UIO_READ) { 8821144e3bSPoul-Henning Kamp bp->b_iocmd = BIO_READ; 89eea7f71cSKonstantin Belousov curthread->td_ru.ru_inblock++; 90eea7f71cSKonstantin Belousov } else { 9121144e3bSPoul-Henning Kamp bp->b_iocmd = BIO_WRITE; 92eea7f71cSKonstantin Belousov curthread->td_ru.ru_oublock++; 93eea7f71cSKonstantin Belousov } 94749ffa4eSJeff Roberson bp->b_iodone = bdone; 954b83b27fSJohn Dyson bp->b_data = uio->uio_iov[i].iov_base; 967179e74fSPoul-Henning Kamp bp->b_bcount = uio->uio_iov[i].iov_len; 977179e74fSPoul-Henning Kamp bp->b_offset = uio->uio_offset; 9801758670SPoul-Henning Kamp bp->b_iooffset = uio->uio_offset; 9916f62314SDavid Greenman bp->b_saveaddr = sa; 1007179e74fSPoul-Henning Kamp 1017179e74fSPoul-Henning Kamp /* Don't exceed drivers iosize limit */ 1027179e74fSPoul-Henning Kamp if (bp->b_bcount > dev->si_iosize_max) 1037179e74fSPoul-Henning Kamp bp->b_bcount = dev->si_iosize_max; 1047179e74fSPoul-Henning Kamp 1057179e74fSPoul-Henning Kamp /* 1067179e74fSPoul-Henning Kamp * Make sure the pbuf can map the request 1077179e74fSPoul-Henning Kamp * XXX: The pbuf has kvasize = MAXPHYS so a request 1087179e74fSPoul-Henning Kamp * XXX: larger than MAXPHYS - PAGE_SIZE must be 1097179e74fSPoul-Henning Kamp * XXX: page aligned or it will be fragmented. 1107179e74fSPoul-Henning Kamp */ 1117179e74fSPoul-Henning Kamp iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK; 1127179e74fSPoul-Henning Kamp if ((bp->b_bcount + iolen) > bp->b_kvasize) { 11393729c17SKenneth D. Merry /* 11493729c17SKenneth D. Merry * This device does not want I/O to be split. 11593729c17SKenneth D. Merry */ 11693729c17SKenneth D. Merry if (dev->si_flags & SI_NOSPLIT) { 117*880e57b6SKenneth D. Merry uprintf("%s: request ptr %p is not " 118*880e57b6SKenneth D. Merry "on a page boundary; cannot split " 11993729c17SKenneth D. Merry "request\n", devtoname(dev), 120aaea33e5SKenneth D. Merry bp->b_data); 12193729c17SKenneth D. Merry error = EFBIG; 12293729c17SKenneth D. Merry goto doerror; 12393729c17SKenneth D. Merry } 1247179e74fSPoul-Henning Kamp bp->b_bcount = bp->b_kvasize; 1257179e74fSPoul-Henning Kamp if (iolen != 0) 1267179e74fSPoul-Henning Kamp bp->b_bcount -= PAGE_SIZE; 1277179e74fSPoul-Henning Kamp } 1287179e74fSPoul-Henning Kamp bp->b_bufsize = bp->b_bcount; 1297179e74fSPoul-Henning Kamp 130e96d018dSPoul-Henning Kamp bp->b_blkno = btodb(bp->b_offset); 13126f9a767SRodney W. Grimes 13231932faeSAlexander Kabaev csw = dev->si_devsw; 133d1e99f43SKonstantin Belousov if (uio->uio_segflg == UIO_USERSPACE) { 134ce625ec7SKenneth D. Merry if (dev->si_flags & SI_UNMAPPED) 13531932faeSAlexander Kabaev mapped = 0; 13631932faeSAlexander Kabaev else 13731932faeSAlexander Kabaev mapped = 1; 13831932faeSAlexander Kabaev if (vmapbuf(bp, mapped) < 0) { 1392d5c7e45SMatthew Dillon error = EFAULT; 1402d5c7e45SMatthew Dillon goto doerror; 1412d5c7e45SMatthew Dillon } 14231932faeSAlexander Kabaev } 14326f9a767SRodney W. Grimes 144d1e99f43SKonstantin Belousov dev_strategy_csw(dev, csw, bp); 145749ffa4eSJeff Roberson if (uio->uio_rw == UIO_READ) 146749ffa4eSJeff Roberson bwait(bp, PRIBIO, "physrd"); 147749ffa4eSJeff Roberson else 148749ffa4eSJeff Roberson bwait(bp, PRIBIO, "physwr"); 14926f9a767SRodney W. Grimes 1506884d2aaSPeter Wemm if (uio->uio_segflg == UIO_USERSPACE) 15126f9a767SRodney W. Grimes vunmapbuf(bp); 1527179e74fSPoul-Henning Kamp iolen = bp->b_bcount - bp->b_resid; 153c244d2deSPoul-Henning Kamp if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR)) 1547d7bb69dSDavid Greenman goto doerror; /* EOF */ 15526f9a767SRodney W. Grimes uio->uio_iov[i].iov_len -= iolen; 1562b7f24d2SMike Barcroft uio->uio_iov[i].iov_base = 1572b7f24d2SMike Barcroft (char *)uio->uio_iov[i].iov_base + iolen; 15826f9a767SRodney W. Grimes uio->uio_resid -= iolen; 15926f9a767SRodney W. Grimes uio->uio_offset += iolen; 160c244d2deSPoul-Henning Kamp if( bp->b_ioflags & BIO_ERROR) { 16126f9a767SRodney W. Grimes error = bp->b_error; 16226f9a767SRodney W. Grimes goto doerror; 16326f9a767SRodney W. Grimes } 16426f9a767SRodney W. Grimes } 16526f9a767SRodney W. Grimes } 16626f9a767SRodney W. Grimes doerror: 1677179e74fSPoul-Henning Kamp relpbuf(bp, NULL); 16857dc5948SPeter Wemm PRELE(curproc); 16926f9a767SRodney W. Grimes return (error); 170df8bae1dSRodney W. Grimes } 171