1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22/*- 23 * Copyright (c) 1982, 1986, 1990, 1993 24 * The Regents of the University of California. All rights reserved. 25 * (c) UNIX System Laboratories, Inc. 26 * All or some portions of this file are derived from material licensed 27 * to the University of California by American Telephone and Telegraph 28 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 29 * the permission of UNIX System Laboratories, Inc. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 1. Redistributions of source code must retain the above copyright 35 * notice, this list of conditions and the following disclaimer. 36 * 2. Redistributions in binary form must reproduce the above copyright 37 * notice, this list of conditions and the following disclaimer in the 38 * documentation and/or other materials provided with the distribution. 39 * 3. All advertising materials mentioning features or use of this software 40 * must display the following acknowledgement: 41 * This product includes software developed by the University of 42 * California, Berkeley and its contributors. 43 * 4. Neither the name of the University nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 * 59 * from: @(#)kern_physio.c 8.1 (Berkeley) 6/10/93 60 */ 61/* 62 * HISTORY 63 * 27-July-97 Umesh Vaishampayan (umeshv@apple.com) 64 * Allow physio() to kernel space. 65 */ 66 67#include <sys/param.h> 68#include <sys/systm.h> 69#include <sys/buf_internal.h> 70#include <sys/conf.h> 71#include <sys/proc_internal.h> 72#include <sys/uio_internal.h> 73 74int 75physio(strategy, bp, dev, flags, minphys, uio, blocksize) 76 void (*strategy)(); 77 buf_t bp; 78 dev_t dev; 79 int flags; 80 u_int (*minphys)(); 81 struct uio *uio; 82 int blocksize; 83{ 84 struct proc *p = current_proc(); 85 int error, i, nobuf, todo, iosize; 86#if LP64KERN 87 int64_t done; 88#else 89 int done; 90#endif 91 92 error = 0; 93 flags &= B_READ | B_WRITE; 94 95 /* 96 * [check user read/write access to the data buffer] 97 * 98 * Check each iov one by one. Note that we know if we're reading or 99 * writing, so we ignore the uio's rw parameter. Also note that if 100 * we're doing a read, that's a *write* to user-space. 101 */ 102 for (i = 0; i < uio->uio_iovcnt; i++) { 103 if(UIO_SEG_IS_USER_SPACE(uio->uio_segflg)) { 104 if (!useracc(uio_iov_base_at(uio, i), 105 uio_iov_len_at(uio, i), 106 (flags == B_READ) ? B_WRITE : B_READ)) 107 return (EFAULT); 108 } 109 } 110 /* Make sure we have a buffer, creating one if necessary. */ 111 if (nobuf = (bp == NULL)) { 112 bp = buf_alloc((vnode_t)0); 113 } 114 115 /* [while the buffer is marked busy] */ 116 while (((error = (int)buf_acquire(bp, 0, 0, 0)) == EAGAIN)); 117 118 if (error) { 119 if (nobuf) 120 buf_free(bp); 121 return (error); 122 } 123 124 /* [set up the fixed part of the buffer for a transfer] */ 125 bp->b_dev = dev; 126 bp->b_proc = p; 127 128 buf_seterror(bp, 0); 129 /* 130 * [while there is data to transfer and no I/O error] 131 * Note that I/O errors are handled with a 'goto' at the bottom 132 * of the 'while' loop. 133 */ 134 for (i = 0; i < uio->uio_iovcnt; i++) { 135 while (uio_iov_len_at(uio, i) > 0) { 136 /* 137 * [mark the buffer busy for physical I/O] 138 * (i.e. set B_PHYS (because it's an I/O to user 139 * memory, and B_RAW, because B_RAW is to be 140 * "Set by physio for raw transfers.", in addition 141 * to the read/write flag.) 142 */ 143 buf_setflags(bp, B_PHYS | B_RAW | flags); 144 145 if ( (iosize = uio_iov_len_at(uio, i)) > MAXPHYSIO_WIRED) 146 iosize = MAXPHYSIO_WIRED; 147 148 /* [set up the buffer for a maximum-sized transfer] */ 149 buf_setblkno(bp, uio->uio_offset / blocksize); 150 buf_setcount(bp, iosize); 151 // LP64todo - fix this! 152 buf_setdataptr(bp, CAST_DOWN(caddr_t, uio_iov_base_at(uio, i))); 153 154 /* 155 * [call minphys to bound the tranfer size] 156 * and remember the amount of data to transfer, 157 * for later comparison. 158 */ 159 (*minphys)(bp); 160 todo = buf_count(bp); 161 162 /* 163 * [lock the part of the user address space involved 164 * in the transfer] 165 */ 166 167 if(UIO_SEG_IS_USER_SPACE(uio->uio_segflg)) 168 vslock(CAST_USER_ADDR_T(buf_dataptr(bp)), 169 (user_size_t)todo); 170 171 /* [call strategy to start the transfer] */ 172 (*strategy)(bp); 173 174 175 /* [wait for the transfer to complete] */ 176 error = (int)buf_biowait(bp); 177 178 /* 179 * [unlock the part of the address space previously 180 * locked] 181 */ 182 if(UIO_SEG_IS_USER_SPACE(uio->uio_segflg)) 183 vsunlock(CAST_USER_ADDR_T(buf_dataptr(bp)), 184 (user_size_t)todo, 185 (flags & B_READ)); 186 187 /* 188 * [deduct the transfer size from the total number 189 * of data to transfer] 190 */ 191 done = buf_count(bp) - buf_resid(bp); 192 uio_iov_len_add_at(uio, -done, i); 193 uio_iov_base_add_at(uio, done, i); 194 uio->uio_offset += done; 195 uio_setresid(uio, (uio_resid(uio) - done)); 196 197 /* 198 * Now, check for an error. 199 * Also, handle weird end-of-disk semantics. 200 */ 201 if (error || done < todo) 202 goto done; 203 } 204 } 205 206done: 207 /* 208 * [clean up the state of the buffer] 209 * Remember if somebody wants it, so we can wake them up below. 210 * Also, if we had to steal it, give it back. 211 */ 212 213 buf_clearflags(bp, B_PHYS | B_RAW); 214 if (nobuf) 215 buf_free(bp); 216 else 217 { 218 buf_drop(bp); 219 } 220 221 return (error); 222} 223 224/* 225 * Leffler, et al., says on p. 231: 226 * "The minphys() routine is called by physio() to adjust the 227 * size of each I/O transfer before the latter is passed to 228 * the strategy routine..." 229 * 230 * so, just adjust the buffer's count accounting to MAXPHYS here, 231 * and return the new count; 232 */ 233u_int 234minphys(bp) 235 struct buf *bp; 236{ 237 238 buf_setcount(bp, min(MAXPHYS, buf_count(bp))); 239 return buf_count(bp); 240} 241 242/* 243 * Do a read on a device for a user process. 244 */ 245rawread(dev, uio) 246 dev_t dev; 247 struct uio *uio; 248{ 249 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 250 dev, B_READ, minphys, uio, DEV_BSIZE)); 251} 252 253/* 254 * Do a write on a device for a user process. 255 */ 256rawwrite(dev, uio) 257 dev_t dev; 258 struct uio *uio; 259{ 260 return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL, 261 dev, B_WRITE, minphys, uio, DEV_BSIZE)); 262} 263

