1 /* 2 * Copyright (c) 1994 John S. Dyson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Absolutely no warranty of function or purpose is made by the author 15 * John S. Dyson. 16 * 4. Modifications may be freely made to this file if the above conditions 17 * are met. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/buf.h> 23 #include <sys/conf.h> 24 #include <sys/proc.h> 25 #include <sys/uio.h> 26 #include <sys/device.h> 27 28 #include <vm/vm.h> 29 #include <vm/vm_extern.h> 30 31 static int 32 physio(cdev_t dev, struct uio *uio, int ioflag) 33 { 34 int i; 35 int error; 36 int saflags; 37 size_t iolen; 38 size_t bcount; 39 caddr_t ubase; 40 struct buf *bp; 41 42 if (uio->uio_segflg == UIO_USERSPACE) 43 bp = getpbuf_mem(NULL); 44 else 45 bp = getpbuf_kva(NULL); 46 saflags = bp->b_flags; 47 error = 0; 48 49 /* XXX: sanity check */ 50 if (dev->si_iosize_max < PAGE_SIZE) { 51 kprintf("WARNING: %s si_iosize_max=%d, using MAXPHYS.\n", 52 devtoname(dev), dev->si_iosize_max); 53 dev->si_iosize_max = MAXPHYS; 54 } 55 56 /* Must be a real uio */ 57 KKASSERT(uio->uio_segflg != UIO_NOCOPY); 58 59 for (i = 0; i < uio->uio_iovcnt; i++) { 60 while (uio->uio_iov[i].iov_len) { 61 if (uio->uio_rw == UIO_READ) 62 bp->b_cmd = BUF_CMD_READ; 63 else 64 bp->b_cmd = BUF_CMD_WRITE; 65 bp->b_flags = saflags; 66 bcount = uio->uio_iov[i].iov_len; 67 68 reinitbufbio(bp); /* clear translation cache */ 69 bp->b_bio1.bio_offset = uio->uio_offset; 70 bp->b_bio1.bio_done = biodone_sync; 71 bp->b_bio1.bio_flags |= BIO_SYNC; 72 73 /* 74 * Setup for mapping the request into kernel memory. 75 * 76 * We can only write as much as fits in a pbuf, 77 * which is MAXPHYS, and no larger then the device's 78 * ability. 79 * 80 * If not using bounce pages the base address of the 81 * user mapping into the pbuf may be offset, further 82 * reducing how much will actually fit in the pbuf. 83 */ 84 if (bcount > dev->si_iosize_max) 85 bcount = dev->si_iosize_max; 86 87 ubase = uio->uio_iov[i].iov_base; 88 iolen = ((vm_offset_t)ubase) & PAGE_MASK; 89 if (bcount > bp->b_kvasize) 90 bcount = bp->b_kvasize; 91 92 /* 93 * If we have to use a bounce buffer allocate kernel 94 * memory and copyin/copyout. Otherwise map the 95 * user buffer directly into kernel memory without 96 * copying. 97 */ 98 if (uio->uio_segflg == UIO_USERSPACE) { 99 bp->b_bcount = bcount; 100 if (uio->uio_rw == UIO_WRITE) { 101 error = copyin(ubase, bp->b_data, bcount); 102 if (error) 103 goto doerror; 104 } 105 } else { 106 bp->b_data = uio->uio_iov[i].iov_base; 107 bp->b_bcount = bcount; 108 } 109 dev_dstrategy(dev, &bp->b_bio1); 110 biowait(&bp->b_bio1, "physstr"); 111 112 iolen = bp->b_bcount - bp->b_resid; 113 if (uio->uio_segflg == UIO_USERSPACE) { 114 if (uio->uio_rw == UIO_READ && iolen) { 115 error = copyout(bp->b_data, ubase, iolen); 116 if (error) { 117 bp->b_flags |= B_ERROR; 118 bp->b_error = error; 119 } 120 } 121 } 122 if (iolen == 0 && !(bp->b_flags & B_ERROR)) 123 goto doerror; /* EOF */ 124 uio->uio_iov[i].iov_len -= iolen; 125 uio->uio_iov[i].iov_base = (char *)uio->uio_iov[i].iov_base + iolen; 126 uio->uio_resid -= iolen; 127 uio->uio_offset += iolen; 128 if (bp->b_flags & B_ERROR) { 129 error = bp->b_error; 130 goto doerror; 131 } 132 } 133 } 134 doerror: 135 relpbuf(bp, NULL); 136 return (error); 137 } 138 139 int 140 physread(struct dev_read_args *ap) 141 { 142 return(physio(ap->a_head.a_dev, ap->a_uio, ap->a_ioflag)); 143 } 144 145 int 146 physwrite(struct dev_write_args *ap) 147 { 148 return(physio(ap->a_head.a_dev, ap->a_uio, ap->a_ioflag)); 149 } 150 151