kern_physio.c revision 1895
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 * $Id: kern_physio.c,v 1.4 1994/08/06 09:15:28 davidg Exp $
20 */
21
22#include <sys/param.h>
23#include <sys/systm.h>
24#include <sys/buf.h>
25#include <sys/conf.h>
26#include <sys/proc.h>
27#include <vm/vm.h>
28
29static void physwakeup();
30u_int minphys(struct buf *bp);
31
32int
33physio(strategy, bp, dev, rw, minp, uio)
34	int (*strategy)();
35	struct buf *bp;
36	dev_t dev;
37	int rw;
38	u_int (*minp)();
39	struct uio *uio;
40{
41	int i;
42	int bufflags = rw?B_READ:0;
43	int error;
44	int spl;
45	caddr_t sa;
46	int bp_alloc = (bp == 0);
47	struct buf *bpa;
48
49/*
50 * keep the process from being swapped
51 */
52	curproc->p_flag |= P_PHYSIO;
53
54	/* create and build a buffer header for a transfer */
55	bpa = (struct buf *)getpbuf();
56	if (!bp_alloc) {
57		spl = splbio();
58		while (bp->b_flags & B_BUSY) {
59			bp->b_flags |= B_WANTED;
60			tsleep((caddr_t)bp, PRIBIO, "physbw", 0);
61		}
62		bp->b_flags |= B_BUSY;
63		splx(spl);
64	} else {
65		bp = bpa;
66	}
67
68	/*
69	 * get a copy of the kva from the physical buffer
70	 */
71	sa = bpa->b_data;
72	bp->b_proc = curproc;
73	bp->b_dev = dev;
74	error = bp->b_error = 0;
75
76	for(i=0;i<uio->uio_iovcnt;i++) {
77		while( uio->uio_iov[i].iov_len) {
78			vm_offset_t v, lastv, pa;
79			caddr_t adr;
80
81			bp->b_bcount = uio->uio_iov[i].iov_len;
82			bp->b_bcount = minp( bp);
83			if( minp != minphys)
84				bp->b_bcount = minphys( bp);
85			bp->b_bufsize = bp->b_bcount;
86			bp->b_flags = B_BUSY | B_PHYS | B_CALL | bufflags;
87			bp->b_iodone = physwakeup;
88			bp->b_data = uio->uio_iov[i].iov_base;
89			/*
90			 * pass in the kva from the physical buffer
91			 * for the temporary kernel mapping.
92			 */
93			bp->b_saveaddr = sa;
94			bp->b_blkno = btodb(uio->uio_offset);
95
96
97			if (rw && !useracc(bp->b_data, bp->b_bufsize, B_WRITE)) {
98				error = EFAULT;
99				goto doerror;
100			}
101			if (!rw && !useracc(bp->b_data, bp->b_bufsize, B_READ)) {
102				error = EFAULT;
103				goto doerror;
104			}
105
106			vmapbuf(bp);
107
108			/* perform transfer */
109			(*strategy)(bp);
110
111			spl = splbio();
112			while ((bp->b_flags & B_DONE) == 0)
113				tsleep((caddr_t)bp, PRIBIO, "physstr", 0);
114			splx(spl);
115
116			vunmapbuf(bp);
117
118			/*
119			 * update the uio data
120			 */
121			{
122				int iolen = bp->b_bcount - bp->b_resid;
123				uio->uio_iov[i].iov_len -= iolen;
124				uio->uio_iov[i].iov_base += iolen;
125				uio->uio_resid -= iolen;
126				uio->uio_offset += iolen;
127			}
128
129			/*
130			 * check for an error
131			 */
132			if( bp->b_flags & B_ERROR) {
133				error = bp->b_error;
134				goto doerror;
135			}
136		}
137	}
138
139
140doerror:
141	relpbuf(bpa);
142	if (!bp_alloc) {
143		bp->b_flags &= ~(B_BUSY|B_PHYS);
144		if( bp->b_flags & B_WANTED) {
145			bp->b_flags &= ~B_WANTED;
146			wakeup((caddr_t)bp);
147		}
148	}
149/*
150 * allow the process to be swapped
151 */
152	curproc->p_flag &= ~P_PHYSIO;
153
154	return (error);
155}
156
157u_int
158minphys(struct buf *bp)
159{
160
161	if( bp->b_bcount > MAXBSIZE) {
162		bp->b_bcount = MAXBSIZE;
163	}
164	return bp->b_bcount;
165}
166
167int
168rawread(dev_t dev, struct uio *uio)
169{
170	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
171	    dev, 1, minphys, uio));
172}
173
174int
175rawwrite(dev_t dev, struct uio *uio)
176{
177	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
178	    dev, 0, minphys, uio));
179}
180
181static void
182physwakeup(bp)
183	struct buf *bp;
184{
185	wakeup((caddr_t) bp);
186	bp->b_flags &= ~B_CALL;
187}
188