kern_physio.c revision 248515
1169695Skan/*-
2169695Skan * Copyright (c) 1994 John S. Dyson
3258826Spfg * All rights reserved.
4258826Spfg *
5169695Skan * Redistribution and use in source and binary forms, with or without
6169695Skan * modification, are permitted provided that the following conditions
7169695Skan * are met:
8169695Skan * 1. Redistributions of source code must retain the above copyright
9169695Skan *    notice immediately at the beginning of the file, without modification,
10169695Skan *    this list of conditions, and the following disclaimer.
11169695Skan * 2. Redistributions in binary form must reproduce the above copyright
12169695Skan *    notice, this list of conditions and the following disclaimer in the
13169695Skan *    documentation and/or other materials provided with the distribution.
14169695Skan * 3. Absolutely no warranty of function or purpose is made by the author
15169695Skan *    John S. Dyson.
16169695Skan * 4. Modifications may be freely made to this file if the above conditions
17169695Skan *    are met.
18169695Skan */
19169695Skan
20169695Skan#include <sys/cdefs.h>
21169695Skan__FBSDID("$FreeBSD: head/sys/kern/kern_physio.c 248515 2013-03-19 14:43:57Z kib $");
22169695Skan
23169695Skan#include <sys/param.h>
24169695Skan#include <sys/systm.h>
25169695Skan#include <sys/bio.h>
26169695Skan#include <sys/buf.h>
27169695Skan#include <sys/conf.h>
28169695Skan#include <sys/proc.h>
29169695Skan#include <sys/uio.h>
30169695Skan
31169695Skan#include <vm/vm.h>
32169695Skan#include <vm/vm_extern.h>
33169695Skan
34169695Skanint
35169695Skanphysio(struct cdev *dev, struct uio *uio, int ioflag)
36169695Skan{
37169695Skan	int i;
38169695Skan	int error;
39169695Skan	caddr_t sa;
40169695Skan	u_int iolen;
41169695Skan	struct buf *bp;
42169695Skan
43169695Skan	/* Keep the process UPAGES from being swapped. XXX: why ? */
44169695Skan	PHOLD(curproc);
45169695Skan
46169695Skan	bp = getpbuf(NULL);
47169695Skan	sa = bp->b_data;
48169695Skan	error = 0;
49169695Skan
50169695Skan	/* XXX: sanity check */
51169695Skan	if(dev->si_iosize_max < PAGE_SIZE) {
52169695Skan		printf("WARNING: %s si_iosize_max=%d, using DFLTPHYS.\n",
53169695Skan		    devtoname(dev), dev->si_iosize_max);
54169695Skan		dev->si_iosize_max = DFLTPHYS;
55169695Skan	}
56169695Skan
57169695Skan	for (i = 0; i < uio->uio_iovcnt; i++) {
58169695Skan		while (uio->uio_iov[i].iov_len) {
59169695Skan			bp->b_flags = 0;
60169695Skan			if (uio->uio_rw == UIO_READ) {
61169695Skan				bp->b_iocmd = BIO_READ;
62169695Skan				curthread->td_ru.ru_inblock++;
63169695Skan			} else {
64169695Skan				bp->b_iocmd = BIO_WRITE;
65169695Skan				curthread->td_ru.ru_oublock++;
66169695Skan			}
67169695Skan			bp->b_iodone = bdone;
68169695Skan			bp->b_data = uio->uio_iov[i].iov_base;
69169695Skan			bp->b_bcount = uio->uio_iov[i].iov_len;
70169695Skan			bp->b_offset = uio->uio_offset;
71169695Skan			bp->b_iooffset = uio->uio_offset;
72169695Skan			bp->b_saveaddr = sa;
73169695Skan
74169695Skan			/* Don't exceed drivers iosize limit */
75169695Skan			if (bp->b_bcount > dev->si_iosize_max)
76169695Skan				bp->b_bcount = dev->si_iosize_max;
77169695Skan
78169695Skan			/*
79169695Skan			 * Make sure the pbuf can map the request
80169695Skan			 * XXX: The pbuf has kvasize = MAXPHYS so a request
81169695Skan			 * XXX: larger than MAXPHYS - PAGE_SIZE must be
82169695Skan			 * XXX: page aligned or it will be fragmented.
83169695Skan			 */
84169695Skan			iolen = ((vm_offset_t) bp->b_data) & PAGE_MASK;
85169695Skan			if ((bp->b_bcount + iolen) > bp->b_kvasize) {
86169695Skan				bp->b_bcount = bp->b_kvasize;
87169695Skan				if (iolen != 0)
88169695Skan					bp->b_bcount -= PAGE_SIZE;
89169695Skan			}
90169695Skan			bp->b_bufsize = bp->b_bcount;
91169695Skan
92169695Skan			bp->b_blkno = btodb(bp->b_offset);
93169695Skan
94169695Skan			if (uio->uio_segflg == UIO_USERSPACE)
95169695Skan				if (vmapbuf(bp, 0) < 0) {
96169695Skan					error = EFAULT;
97169695Skan					goto doerror;
98169695Skan				}
99169695Skan
100169695Skan			dev_strategy(dev, bp);
101169695Skan			if (uio->uio_rw == UIO_READ)
102169695Skan				bwait(bp, PRIBIO, "physrd");
103169695Skan			else
104169695Skan				bwait(bp, PRIBIO, "physwr");
105169695Skan
106169695Skan			if (uio->uio_segflg == UIO_USERSPACE)
107169695Skan				vunmapbuf(bp);
108169695Skan			iolen = bp->b_bcount - bp->b_resid;
109169695Skan			if (iolen == 0 && !(bp->b_ioflags & BIO_ERROR))
110169695Skan				goto doerror;	/* EOF */
111169695Skan			uio->uio_iov[i].iov_len -= iolen;
112169695Skan			uio->uio_iov[i].iov_base =
113169695Skan			    (char *)uio->uio_iov[i].iov_base + iolen;
114169695Skan			uio->uio_resid -= iolen;
115169695Skan			uio->uio_offset += iolen;
116169695Skan			if( bp->b_ioflags & BIO_ERROR) {
117169695Skan				error = bp->b_error;
118169695Skan				goto doerror;
119169695Skan			}
120169695Skan		}
121169695Skan	}
122169695Skandoerror:
123169695Skan	relpbuf(bp, NULL);
124169695Skan	PRELE(curproc);
125169695Skan	return (error);
126169695Skan}
127169695Skan