1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999-2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/debug.h> 31 #include <sys/cmn_err.h> 32 #include <sys/kmem.h> 33 #include <sys/sysmacros.h> 34 #include <sys/buf.h> 35 #include <sys/user.h> 36 #include <sys/proc.h> 37 #include <sys/systm.h> 38 #include <sys/vmsystm.h> 39 #include <sys/mman.h> 40 #include <sys/vm.h> 41 #include <sys/ddi.h> 42 43 #include <vm/as.h> 44 #include <vm/page.h> 45 46 /* 47 * Prepare for raw I/O request - derived from default_physio() 48 * This is the 'setup' portion of physio, limited to dealing 49 * with unstructured access to a single range of user space addresses. 50 * 51 * This is quite limited in functionality compared to physio(). 52 * 53 * 1. allocate and return buf header 54 * 2. lock down user pages and verify access protections 55 * 56 * Use B_READ (S_WRITE) for unstructured access. (We don't know the 57 * direction of the transfer, so use the safest.) 58 */ 59 60 int 61 fc_physio_setup(struct buf **bpp, void *io_base, size_t io_len) 62 { 63 struct proc *procp; 64 struct as *asp; 65 int error = 0; 66 page_t **pplist; 67 struct buf *bp = *bpp; 68 69 bp = getrbuf(KM_SLEEP); 70 bp->b_iodone = NULL; 71 bp->b_resid = 0; 72 *bpp = bp; 73 74 /* segflg *is always* UIO_USERSPACE for us */ 75 procp = ttoproc(curthread); 76 asp = procp->p_as; 77 78 ASSERT(SEMA_HELD(&bp->b_sem)); 79 80 bp->b_error = 0; 81 bp->b_proc = procp; 82 83 bp->b_flags = B_BUSY | B_PHYS | B_READ; 84 bp->b_edev = 0; 85 bp->b_lblkno = 0; 86 87 /* 88 * Don't count on b_addr remaining untouched by the 89 * code below (it may be reset because someone does 90 * a bp_mapin on the buffer). 91 */ 92 bp->b_un.b_addr = io_base; 93 bp->b_bcount = io_len; 94 95 error = as_pagelock(asp, &pplist, io_base, io_len, S_WRITE); 96 97 if (error != 0) { 98 bp->b_flags |= B_ERROR; 99 bp->b_error = error; 100 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS); 101 freerbuf(bp); 102 *bpp = NULL; 103 return (error); 104 } 105 106 bp->b_shadow = pplist; 107 if (pplist != NULL) { 108 bp->b_flags |= B_SHADOW; 109 } 110 return (0); 111 } 112 113 /* 114 * unlock the pages and free the buf header, if we allocated it. 115 */ 116 void 117 fc_physio_free(struct buf **bpp, void *io_base, size_t io_len) 118 { 119 struct buf *bp = *bpp; 120 page_t **pplist = NULL; 121 122 /* 123 * unlock the pages 124 */ 125 126 if (bp->b_flags & B_SHADOW) 127 pplist = bp->b_shadow; 128 129 as_pageunlock(bp->b_proc->p_as, pplist, io_base, io_len, S_WRITE); 130 131 bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_SHADOW); 132 133 freerbuf(bp); 134 *bpp = NULL; 135 } 136