kern_physio.c revision 108586
1168404Spjd/*
2168404Spjd * Copyright (c) 1994 John S. Dyson
3168404Spjd * All rights reserved.
4168404Spjd *
5168404Spjd * Redistribution and use in source and binary forms, with or without
6168404Spjd * modification, are permitted provided that the following conditions
7168404Spjd * are met:
8168404Spjd * 1. Redistributions of source code must retain the above copyright
9168404Spjd *    notice immediately at the beginning of the file, without modification,
10168404Spjd *    this list of conditions, and the following disclaimer.
11168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
12168404Spjd *    notice, this list of conditions and the following disclaimer in the
13168404Spjd *    documentation and/or other materials provided with the distribution.
14168404Spjd * 3. Absolutely no warranty of function or purpose is made by the author
15168404Spjd *    John S. Dyson.
16168404Spjd * 4. Modifications may be freely made to this file if the above conditions
17168404Spjd *    are met.
18168404Spjd *
19168404Spjd * $FreeBSD: head/sys/kern/kern_physio.c 108586 2003-01-03 05:57:35Z phk $
20168404Spjd */
21236884Smm
22168404Spjd#include <sys/param.h>
23219089Spjd#include <sys/systm.h>
24168404Spjd#include <sys/bio.h>
25168404Spjd#include <sys/buf.h>
26168404Spjd#include <sys/conf.h>
27168404Spjd#include <sys/proc.h>
28236884Smm#include <sys/uio.h>
29236884Smm
30236884Smm#include <vm/vm.h>
31236884Smm#include <vm/vm_extern.h>
32168404Spjd
33168404Spjdstatic void
34168404Spjdphyswakeup(struct buf *bp)
35168404Spjd{
36168404Spjd	wakeup(bp);
37168404Spjd}
38168404Spjd
39168404Spjdint
40168404Spjdphysio(dev_t dev, struct uio *uio, int ioflag)
41168404Spjd{
42168404Spjd	int i;
43168404Spjd	int error;
44168404Spjd	int spl;
45168404Spjd	caddr_t sa;
46168404Spjd	u_int iolen;
47168404Spjd	struct buf *bp;
48168404Spjd
49168404Spjd	/* Keep the process UPAGES from being swapped. XXX: why ? */
50168404Spjd	PHOLD(curproc);
51168404Spjd
52168404Spjd	bp = getpbuf(NULL);
53168404Spjd	sa = bp->b_data;
54168404Spjd	error = bp->b_error = 0;
55168404Spjd
56168404Spjd	/* XXX: sanity check */
57168404Spjd	if(dev->si_iosize_max < PAGE_SIZE) {
58168404Spjd		printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n",
59168404Spjd		    devtoname(dev), dev->si_iosize_max);
60168404Spjd		dev->si_iosize_max = DFLTPHYS;
61168404Spjd	}
62168404Spjd
63168404Spjd	for (i = 0; i < uio->uio_iovcnt; i++) {
64168404Spjd		while (uio->uio_iov[i].iov_len) {
65168404Spjd			bp->b_flags = B_PHYS;
66168404Spjd			if (uio->uio_rw == UIO_READ)
67168404Spjd				bp->b_iocmd = BIO_READ;
68168404Spjd			else
69168404Spjd				bp->b_iocmd = BIO_WRITE;
70168404Spjd			bp->b_dev = dev;
71168404Spjd			bp->b_iodone = physwakeup;
72168404Spjd			bp->b_data = uio->uio_iov[i].iov_base;
73168404Spjd			bp->b_bcount = uio->uio_iov[i].iov_len;
74168404Spjd			bp->b_offset = uio->uio_offset;
75168404Spjd			bp->b_saveaddr = sa;
76168404Spjd
77168404Spjd			/* Don't exceed drivers iosize limit */
78168404Spjd			if (bp->b_bcount > dev->si_iosize_max)
79168404Spjd				bp->b_bcount = dev->si_iosize_max;
80168404Spjd
81168926Spjd			/*
82168404Spjd			 * Make sure the pbuf can map the request
83168926Spjd			 * XXX: The pbuf has kvasize = MAXPHYS so a request
84168926Spjd			 * XXX: larger than MAXPHYS - PAGE_SIZE must be
85168404Spjd			 * XXX: page aligned or it will be fragmented.
86168404Spjd			 */
87168404Spjd			iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK;
88168404Spjd			if ((bp->b_bcount + iolen) > bp->b_kvasize) {
89168404Spjd				bp->b_bcount = bp->b_kvasize;
90168404Spjd				if (iolen != 0)
91168404Spjd					bp->b_bcount -= PAGE_SIZE;
92168404Spjd			}
93168404Spjd			bp->b_bufsize = bp->b_bcount;
94168404Spjd
95168404Spjd			bp->b_blkno = btodb(bp->b_offset);
96168404Spjd
97168404Spjd			if (uio->uio_segflg == UIO_USERSPACE) {
98168404Spjd				if (!useracc(bp->b_data, bp->b_bufsize,
99168404Spjd				    bp->b_iocmd == BIO_READ ?
100168404Spjd				    VM_PROT_WRITE : VM_PROT_READ)) {
101168404Spjd					error = EFAULT;
102168404Spjd					goto doerror;
103168404Spjd				}
104168404Spjd				vmapbuf(bp);
105168404Spjd			}
106168404Spjd
107168404Spjd			DEV_STRATEGY(bp);
108168404Spjd			spl = splbio();
109168404Spjd			while ((bp->b_flags & B_DONE) == 0)
110168926Spjd				tsleep(bp, PRIBIO, "physstr", 0);
111168404Spjd			splx(spl);
112168404Spjd
113168404Spjd			if (uio->uio_segflg == UIO_USERSPACE)
114168404Spjd				vunmapbuf(bp);
115168404Spjd			iolen = bp->b_bcount - bp->b_resid;
116168404Spjd			if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR))
117168404Spjd				goto doerror;	/* EOF */
118168404Spjd			uio->uio_iov[i].iov_len -= iolen;
119168404Spjd			uio->uio_iov[i].iov_base =
120168404Spjd			    (char *)uio->uio_iov[i].iov_base + iolen;
121168404Spjd			uio->uio_resid -= iolen;
122168404Spjd			uio->uio_offset += iolen;
123168404Spjd			if( bp->b_ioflags & BIO_ERROR) {
124168404Spjd				error = bp->b_error;
125168404Spjd				goto doerror;
126168404Spjd			}
127168404Spjd		}
128168404Spjd	}
129168404Spjddoerror:
130168404Spjd	relpbuf(bp, NULL);
131168404Spjd	PRELE(curproc);
132168404Spjd	return (error);
133168404Spjd}
134168404Spjd