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> 28*869fd29aSAlexander Motin #include <sys/malloc.h> 29df8bae1dSRodney W. Grimes #include <sys/proc.h> 3008637435SBruce Evans #include <sys/uio.h> 31*869fd29aSAlexander Motin #include <geom/geom.h> 3208637435SBruce Evans 3326f9a767SRodney W. Grimes #include <vm/vm.h> 34*869fd29aSAlexander Motin #include <vm/vm_page.h> 35efeaf95aSDavid Greenman #include <vm/vm_extern.h> 36*869fd29aSAlexander Motin #include <vm/vm_map.h> 37df8bae1dSRodney W. Grimes 38c48d1775SPoul-Henning Kamp int 3989c9c53dSPoul-Henning Kamp physio(struct cdev *dev, struct uio *uio, int ioflag) 40df8bae1dSRodney W. Grimes { 41*869fd29aSAlexander Motin struct buf *pbuf; 42*869fd29aSAlexander Motin struct bio *bp; 43*869fd29aSAlexander Motin struct vm_page **pages; 4416f62314SDavid Greenman caddr_t sa; 45*869fd29aSAlexander Motin u_int iolen, poff; 46*869fd29aSAlexander Motin int error, i, npages, maxpages; 47*869fd29aSAlexander Motin vm_prot_t prot; 4826f9a767SRodney W. Grimes 497179e74fSPoul-Henning Kamp /* XXX: sanity check */ 507179e74fSPoul-Henning Kamp if(dev->si_iosize_max < PAGE_SIZE) { 517179e74fSPoul-Henning Kamp printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n", 527179e74fSPoul-Henning Kamp devtoname(dev), dev->si_iosize_max); 537179e74fSPoul-Henning Kamp dev->si_iosize_max = DFLTPHYS; 547179e74fSPoul-Henning Kamp } 557179e74fSPoul-Henning Kamp 5693729c17SKenneth D. Merry /* 5793729c17SKenneth D. Merry * If the driver does not want I/O to be split, that means that we 5893729c17SKenneth D. Merry * need to reject any requests that will not fit into one buffer. 5993729c17SKenneth D. Merry */ 60880e57b6SKenneth D. Merry if (dev->si_flags & SI_NOSPLIT && 61880e57b6SKenneth D. Merry (uio->uio_resid > dev->si_iosize_max || uio->uio_resid > MAXPHYS || 62880e57b6SKenneth D. Merry uio->uio_iovcnt > 1)) { 6393729c17SKenneth D. Merry /* 6493729c17SKenneth D. Merry * Tell the user why his I/O was rejected. 6593729c17SKenneth D. Merry */ 6693729c17SKenneth D. Merry if (uio->uio_resid > dev->si_iosize_max) 67880e57b6SKenneth D. Merry uprintf("%s: request size=%zd > si_iosize_max=%d; " 6893729c17SKenneth D. Merry "cannot split request\n", devtoname(dev), 6993729c17SKenneth D. Merry uio->uio_resid, dev->si_iosize_max); 7093729c17SKenneth D. Merry if (uio->uio_resid > MAXPHYS) 71880e57b6SKenneth D. Merry uprintf("%s: request size=%zd > MAXPHYS=%d; " 7293729c17SKenneth D. Merry "cannot split request\n", devtoname(dev), 7393729c17SKenneth D. Merry uio->uio_resid, MAXPHYS); 7493729c17SKenneth D. Merry if (uio->uio_iovcnt > 1) 75880e57b6SKenneth D. Merry uprintf("%s: request vectors=%d > 1; " 7693729c17SKenneth D. Merry "cannot split request\n", devtoname(dev), 7793729c17SKenneth D. Merry uio->uio_iovcnt); 78*869fd29aSAlexander Motin return (EFBIG); 7993729c17SKenneth D. Merry } 8093729c17SKenneth D. Merry 81*869fd29aSAlexander Motin /* 82*869fd29aSAlexander Motin * Keep the process UPAGES from being swapped. Processes swapped 83*869fd29aSAlexander Motin * out while holding pbufs, used by swapper, may lead to deadlock. 84*869fd29aSAlexander Motin */ 85*869fd29aSAlexander Motin PHOLD(curproc); 86*869fd29aSAlexander Motin 87*869fd29aSAlexander Motin bp = g_alloc_bio(); 88*869fd29aSAlexander Motin if (uio->uio_segflg != UIO_USERSPACE) { 89*869fd29aSAlexander Motin pbuf = NULL; 90*869fd29aSAlexander Motin pages = NULL; 91*869fd29aSAlexander Motin } else if ((dev->si_flags & SI_UNMAPPED) && unmapped_buf_allowed) { 92*869fd29aSAlexander Motin pbuf = NULL; 93*869fd29aSAlexander Motin maxpages = btoc(MIN(uio->uio_resid, MAXPHYS)) + 1; 94*869fd29aSAlexander Motin pages = malloc(sizeof(*pages) * maxpages, M_DEVBUF, M_WAITOK); 95*869fd29aSAlexander Motin } else { 96*869fd29aSAlexander Motin pbuf = getpbuf(NULL); 97*869fd29aSAlexander Motin sa = pbuf->b_data; 98*869fd29aSAlexander Motin maxpages = btoc(MAXPHYS); 99*869fd29aSAlexander Motin pages = pbuf->b_pages; 100*869fd29aSAlexander Motin } 101*869fd29aSAlexander Motin prot = VM_PROT_READ; 102*869fd29aSAlexander Motin if (uio->uio_rw == UIO_READ) 103*869fd29aSAlexander Motin prot |= VM_PROT_WRITE; /* Less backwards than it looks */ 104*869fd29aSAlexander Motin error = 0; 10526f9a767SRodney W. Grimes for (i = 0; i < uio->uio_iovcnt; i++) { 10626f9a767SRodney W. Grimes while (uio->uio_iov[i].iov_len) { 107*869fd29aSAlexander Motin bzero(bp, sizeof(*bp)); 108eea7f71cSKonstantin Belousov if (uio->uio_rw == UIO_READ) { 109*869fd29aSAlexander Motin bp->bio_cmd = BIO_READ; 110eea7f71cSKonstantin Belousov curthread->td_ru.ru_inblock++; 111eea7f71cSKonstantin Belousov } else { 112*869fd29aSAlexander Motin bp->bio_cmd = BIO_WRITE; 113eea7f71cSKonstantin Belousov curthread->td_ru.ru_oublock++; 114eea7f71cSKonstantin Belousov } 115*869fd29aSAlexander Motin bp->bio_offset = uio->uio_offset; 116*869fd29aSAlexander Motin bp->bio_data = uio->uio_iov[i].iov_base; 117*869fd29aSAlexander Motin bp->bio_length = uio->uio_iov[i].iov_len; 118*869fd29aSAlexander Motin if (bp->bio_length > dev->si_iosize_max) 119*869fd29aSAlexander Motin bp->bio_length = dev->si_iosize_max; 120*869fd29aSAlexander Motin if (bp->bio_length > MAXPHYS) 121*869fd29aSAlexander Motin bp->bio_length = MAXPHYS; 1227179e74fSPoul-Henning Kamp 1237179e74fSPoul-Henning Kamp /* 124*869fd29aSAlexander Motin * Make sure the pbuf can map the request. 125*869fd29aSAlexander Motin * The pbuf has kvasize = MAXPHYS, so a request 126*869fd29aSAlexander Motin * larger than MAXPHYS - PAGE_SIZE must be 127*869fd29aSAlexander Motin * page aligned or it will be fragmented. 1287179e74fSPoul-Henning Kamp */ 129*869fd29aSAlexander Motin poff = (vm_offset_t)bp->bio_data & PAGE_MASK; 130*869fd29aSAlexander Motin if (pbuf && bp->bio_length + poff > pbuf->b_kvasize) { 13193729c17SKenneth D. Merry if (dev->si_flags & SI_NOSPLIT) { 132880e57b6SKenneth D. Merry uprintf("%s: request ptr %p is not " 133880e57b6SKenneth D. Merry "on a page boundary; cannot split " 13493729c17SKenneth D. Merry "request\n", devtoname(dev), 135*869fd29aSAlexander Motin bp->bio_data); 13693729c17SKenneth D. Merry error = EFBIG; 13793729c17SKenneth D. Merry goto doerror; 13893729c17SKenneth D. Merry } 139*869fd29aSAlexander Motin bp->bio_length = pbuf->b_kvasize; 140*869fd29aSAlexander Motin if (poff != 0) 141*869fd29aSAlexander Motin bp->bio_length -= PAGE_SIZE; 1427179e74fSPoul-Henning Kamp } 1437179e74fSPoul-Henning Kamp 144*869fd29aSAlexander Motin bp->bio_bcount = bp->bio_length; 145*869fd29aSAlexander Motin bp->bio_dev = dev; 14626f9a767SRodney W. Grimes 147*869fd29aSAlexander Motin if (pages) { 148*869fd29aSAlexander Motin if ((npages = vm_fault_quick_hold_pages( 149*869fd29aSAlexander Motin &curproc->p_vmspace->vm_map, 150*869fd29aSAlexander Motin (vm_offset_t)bp->bio_data, bp->bio_length, 151*869fd29aSAlexander Motin prot, pages, maxpages)) < 0) { 1522d5c7e45SMatthew Dillon error = EFAULT; 1532d5c7e45SMatthew Dillon goto doerror; 1542d5c7e45SMatthew Dillon } 155*869fd29aSAlexander Motin if (pbuf) { 156*869fd29aSAlexander Motin pmap_qenter((vm_offset_t)sa, 157*869fd29aSAlexander Motin pages, npages); 158*869fd29aSAlexander Motin bp->bio_data = sa + poff; 159*869fd29aSAlexander Motin } else { 160*869fd29aSAlexander Motin bp->bio_ma = pages; 161*869fd29aSAlexander Motin bp->bio_ma_n = npages; 162*869fd29aSAlexander Motin bp->bio_ma_offset = poff; 163*869fd29aSAlexander Motin bp->bio_data = unmapped_buf; 164*869fd29aSAlexander Motin bp->bio_flags |= BIO_UNMAPPED; 165*869fd29aSAlexander Motin } 16631932faeSAlexander Kabaev } 16726f9a767SRodney W. Grimes 168*869fd29aSAlexander Motin dev->si_devsw->d_strategy(bp); 169749ffa4eSJeff Roberson if (uio->uio_rw == UIO_READ) 170*869fd29aSAlexander Motin biowait(bp, "physrd"); 171749ffa4eSJeff Roberson else 172*869fd29aSAlexander Motin biowait(bp, "physwr"); 17326f9a767SRodney W. Grimes 174*869fd29aSAlexander Motin if (pages) { 175*869fd29aSAlexander Motin if (pbuf) 176*869fd29aSAlexander Motin pmap_qremove((vm_offset_t)sa, npages); 177*869fd29aSAlexander Motin vm_page_unhold_pages(pages, npages); 178*869fd29aSAlexander Motin } 179*869fd29aSAlexander Motin 180*869fd29aSAlexander Motin iolen = bp->bio_length - bp->bio_resid; 181*869fd29aSAlexander Motin if (iolen == 0 && !(bp->bio_flags & BIO_ERROR)) 1827d7bb69dSDavid Greenman goto doerror; /* EOF */ 18326f9a767SRodney W. Grimes uio->uio_iov[i].iov_len -= iolen; 1842b7f24d2SMike Barcroft uio->uio_iov[i].iov_base = 1852b7f24d2SMike Barcroft (char *)uio->uio_iov[i].iov_base + iolen; 18626f9a767SRodney W. Grimes uio->uio_resid -= iolen; 18726f9a767SRodney W. Grimes uio->uio_offset += iolen; 188*869fd29aSAlexander Motin if (bp->bio_flags & BIO_ERROR) { 189*869fd29aSAlexander Motin error = bp->bio_error; 19026f9a767SRodney W. Grimes goto doerror; 19126f9a767SRodney W. Grimes } 19226f9a767SRodney W. Grimes } 19326f9a767SRodney W. Grimes } 19426f9a767SRodney W. Grimes doerror: 195*869fd29aSAlexander Motin if (pbuf) 196*869fd29aSAlexander Motin relpbuf(pbuf, NULL); 197*869fd29aSAlexander Motin else if (pages) 198*869fd29aSAlexander Motin free(pages, M_DEVBUF); 199*869fd29aSAlexander Motin g_destroy_bio(bp); 20057dc5948SPeter Wemm PRELE(curproc); 20126f9a767SRodney W. Grimes return (error); 202df8bae1dSRodney W. Grimes } 203