1139804Simp/*- 21549Srgrimes * Copyright (c) 1994 John S. Dyson 31549Srgrimes * All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91549Srgrimes * notice immediately at the beginning of the file, without modification, 101549Srgrimes * this list of conditions, and the following disclaimer. 111541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer in the 131541Srgrimes * documentation and/or other materials provided with the distribution. 141549Srgrimes * 3. Absolutely no warranty of function or purpose is made by the author 151549Srgrimes * John S. Dyson. 161549Srgrimes * 4. Modifications may be freely made to this file if the above conditions 171549Srgrimes * are met. 181541Srgrimes */ 191541Srgrimes 20116182Sobrien#include <sys/cdefs.h> 21116182Sobrien__FBSDID("$FreeBSD$"); 22116182Sobrien 231541Srgrimes#include <sys/param.h> 241541Srgrimes#include <sys/systm.h> 2560041Sphk#include <sys/bio.h> 261541Srgrimes#include <sys/buf.h> 271541Srgrimes#include <sys/conf.h> 281541Srgrimes#include <sys/proc.h> 2934924Sbde#include <sys/uio.h> 3034924Sbde 311549Srgrimes#include <vm/vm.h> 3212662Sdg#include <vm/vm_extern.h> 331541Srgrimes 3446625Sphkint 35130585Sphkphysio(struct cdev *dev, struct uio *uio, int ioflag) 3646625Sphk{ 37248792Skib struct buf *bp; 38248792Skib struct cdevsw *csw; 391887Sdg caddr_t sa; 4052066Sphk u_int iolen; 41248792Skib int error, i, mapped; 421541Srgrimes 4352066Sphk /* Keep the process UPAGES from being swapped. XXX: why ? */ 4445358Speter PHOLD(curproc); 451549Srgrimes 4652066Sphk bp = getpbuf(NULL); 4752066Sphk sa = bp->b_data; 48113149Salc error = 0; 491549Srgrimes 5052066Sphk /* XXX: sanity check */ 5152066Sphk if(dev->si_iosize_max < PAGE_SIZE) { 5252066Sphk printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n", 5352066Sphk devtoname(dev), dev->si_iosize_max); 5452066Sphk dev->si_iosize_max = DFLTPHYS; 5552066Sphk } 5652066Sphk 57254760Sken /* 58254760Sken * If the driver does not want I/O to be split, that means that we 59254760Sken * need to reject any requests that will not fit into one buffer. 60254760Sken */ 61255032Sken if (dev->si_flags & SI_NOSPLIT && 62255032Sken (uio->uio_resid > dev->si_iosize_max || uio->uio_resid > MAXPHYS || 63255032Sken uio->uio_iovcnt > 1)) { 64254760Sken /* 65254760Sken * Tell the user why his I/O was rejected. 66254760Sken */ 67254760Sken if (uio->uio_resid > dev->si_iosize_max) 68255032Sken uprintf("%s: request size=%zd > si_iosize_max=%d; " 69254760Sken "cannot split request\n", devtoname(dev), 70254760Sken uio->uio_resid, dev->si_iosize_max); 71254760Sken if (uio->uio_resid > MAXPHYS) 72255032Sken uprintf("%s: request size=%zd > MAXPHYS=%d; " 73254760Sken "cannot split request\n", devtoname(dev), 74254760Sken uio->uio_resid, MAXPHYS); 75254760Sken if (uio->uio_iovcnt > 1) 76255032Sken uprintf("%s: request vectors=%d > 1; " 77254760Sken "cannot split request\n", devtoname(dev), 78254760Sken uio->uio_iovcnt); 79254760Sken 80254760Sken error = EFBIG; 81254760Sken goto doerror; 82254760Sken } 83254760Sken 8448225Smckusick for (i = 0; i < uio->uio_iovcnt; i++) { 8548225Smckusick while (uio->uio_iov[i].iov_len) { 86122747Sphk bp->b_flags = 0; 87215838Skib if (uio->uio_rw == UIO_READ) { 8858345Sphk bp->b_iocmd = BIO_READ; 89215838Skib curthread->td_ru.ru_inblock++; 90215838Skib } else { 9158345Sphk bp->b_iocmd = BIO_WRITE; 92215838Skib curthread->td_ru.ru_oublock++; 93215838Skib } 94112183Sjeff bp->b_iodone = bdone; 9516752Sdyson bp->b_data = uio->uio_iov[i].iov_base; 9652066Sphk bp->b_bcount = uio->uio_iov[i].iov_len; 9752066Sphk bp->b_offset = uio->uio_offset; 98121223Sphk bp->b_iooffset = uio->uio_offset; 9952066Sphk bp->b_saveaddr = sa; 10052066Sphk 10152066Sphk /* Don't exceed drivers iosize limit */ 10252066Sphk if (bp->b_bcount > dev->si_iosize_max) 10352066Sphk bp->b_bcount = dev->si_iosize_max; 10452066Sphk 10552066Sphk /* 10652066Sphk * Make sure the pbuf can map the request 10752066Sphk * XXX: The pbuf has kvasize = MAXPHYS so a request 10852066Sphk * XXX: larger than MAXPHYS - PAGE_SIZE must be 10952066Sphk * XXX: page aligned or it will be fragmented. 11052066Sphk */ 11152066Sphk iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK; 11252066Sphk if ((bp->b_bcount + iolen) > bp->b_kvasize) { 113254760Sken /* 114254760Sken * This device does not want I/O to be split. 115254760Sken */ 116254760Sken if (dev->si_flags & SI_NOSPLIT) { 117255032Sken uprintf("%s: request ptr %p is not " 118255032Sken "on a page boundary; cannot split " 119254760Sken "request\n", devtoname(dev), 120254802Sken bp->b_data); 121254760Sken error = EFBIG; 122254760Sken goto doerror; 123254760Sken } 12452066Sphk bp->b_bcount = bp->b_kvasize; 12552066Sphk if (iolen != 0) 12652066Sphk bp->b_bcount -= PAGE_SIZE; 12752066Sphk } 1281549Srgrimes bp->b_bufsize = bp->b_bcount; 12952066Sphk 13096848Sphk bp->b_blkno = btodb(bp->b_offset); 1311549Srgrimes 132248792Skib csw = dev->si_devsw; 133248712Skan if (uio->uio_segflg == UIO_USERSPACE) { 134254389Sken if (dev->si_flags & SI_UNMAPPED) 135248712Skan mapped = 0; 136248712Skan else 137248712Skan mapped = 1; 138248712Skan if (vmapbuf(bp, mapped) < 0) { 139109572Sdillon error = EFAULT; 140109572Sdillon goto doerror; 141109572Sdillon } 142248712Skan } 1431549Srgrimes 144248792Skib dev_strategy_csw(dev, csw, bp); 145112183Sjeff if (uio->uio_rw == UIO_READ) 146112183Sjeff bwait(bp, PRIBIO, "physrd"); 147112183Sjeff else 148112183Sjeff bwait(bp, PRIBIO, "physwr"); 1491549Srgrimes 15012498Speter if (uio->uio_segflg == UIO_USERSPACE) 15112498Speter vunmapbuf(bp); 15252066Sphk iolen = bp->b_bcount - bp->b_resid; 15358934Sphk if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR)) 15452066Sphk goto doerror; /* EOF */ 15552066Sphk uio->uio_iov[i].iov_len -= iolen; 156104908Smike uio->uio_iov[i].iov_base = 157104908Smike (char *)uio->uio_iov[i].iov_base + iolen; 15852066Sphk uio->uio_resid -= iolen; 15952066Sphk uio->uio_offset += iolen; 16058934Sphk if( bp->b_ioflags & BIO_ERROR) { 1611549Srgrimes error = bp->b_error; 1621549Srgrimes goto doerror; 1631549Srgrimes } 1641549Srgrimes } 1651549Srgrimes } 1661549Srgrimesdoerror: 16752066Sphk relpbuf(bp, NULL); 16845358Speter PRELE(curproc); 1691549Srgrimes return (error); 1701541Srgrimes} 171