xref: /freebsd/sys/kern/kern_physio.c (revision 7d7bb69d413902bf568dfb4135f014138ddea27a)
126f9a767SRodney W. Grimes /*
226f9a767SRodney W. Grimes  * Copyright (c) 1994 John S. Dyson
326f9a767SRodney W. Grimes  * All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
926f9a767SRodney W. Grimes  *    notice immediately at the beginning of the file, without modification,
1026f9a767SRodney W. Grimes  *    this list of conditions, and the following disclaimer.
11df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
12df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
13df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
1426f9a767SRodney W. Grimes  * 3. Absolutely no warranty of function or purpose is made by the author
1526f9a767SRodney W. Grimes  *    John S. Dyson.
1626f9a767SRodney W. Grimes  * 4. Modifications may be freely made to this file if the above conditions
1726f9a767SRodney W. Grimes  *    are met.
183c4dd356SDavid Greenman  *
197d7bb69dSDavid Greenman  * $Id: kern_physio.c,v 1.5 1994/08/07 13:10:31 davidg Exp $
20df8bae1dSRodney W. Grimes  */
21df8bae1dSRodney W. Grimes 
22df8bae1dSRodney W. Grimes #include <sys/param.h>
23df8bae1dSRodney W. Grimes #include <sys/systm.h>
24df8bae1dSRodney W. Grimes #include <sys/buf.h>
25df8bae1dSRodney W. Grimes #include <sys/conf.h>
26df8bae1dSRodney W. Grimes #include <sys/proc.h>
2726f9a767SRodney W. Grimes #include <vm/vm.h>
28df8bae1dSRodney W. Grimes 
2926f9a767SRodney W. Grimes static void physwakeup();
30a481f200SDavid Greenman u_int minphys(struct buf *bp);
3126f9a767SRodney W. Grimes 
3226f9a767SRodney W. Grimes int
3326f9a767SRodney W. Grimes physio(strategy, bp, dev, rw, minp, uio)
3426f9a767SRodney W. Grimes 	int (*strategy)();
3526f9a767SRodney W. Grimes 	struct buf *bp;
3626f9a767SRodney W. Grimes 	dev_t dev;
3726f9a767SRodney W. Grimes 	int rw;
3826f9a767SRodney W. Grimes 	u_int (*minp)();
3926f9a767SRodney W. Grimes 	struct uio *uio;
40df8bae1dSRodney W. Grimes {
4126f9a767SRodney W. Grimes 	int i;
4226f9a767SRodney W. Grimes 	int bufflags = rw?B_READ:0;
4326f9a767SRodney W. Grimes 	int error;
4426f9a767SRodney W. Grimes 	int spl;
4516f62314SDavid Greenman 	caddr_t sa;
4616f62314SDavid Greenman 	int bp_alloc = (bp == 0);
4716f62314SDavid Greenman 	struct buf *bpa;
48df8bae1dSRodney W. Grimes 
49df8bae1dSRodney W. Grimes /*
5026f9a767SRodney W. Grimes  * keep the process from being swapped
51df8bae1dSRodney W. Grimes  */
5226f9a767SRodney W. Grimes 	curproc->p_flag |= P_PHYSIO;
5326f9a767SRodney W. Grimes 
5426f9a767SRodney W. Grimes 	/* create and build a buffer header for a transfer */
5516f62314SDavid Greenman 	bpa = (struct buf *)getpbuf();
5616f62314SDavid Greenman 	if (!bp_alloc) {
5726f9a767SRodney W. Grimes 		spl = splbio();
5826f9a767SRodney W. Grimes 		while (bp->b_flags & B_BUSY) {
5926f9a767SRodney W. Grimes 			bp->b_flags |= B_WANTED;
6026f9a767SRodney W. Grimes 			tsleep((caddr_t)bp, PRIBIO, "physbw", 0);
6126f9a767SRodney W. Grimes 		}
6226f9a767SRodney W. Grimes 		bp->b_flags |= B_BUSY;
6326f9a767SRodney W. Grimes 		splx(spl);
6416f62314SDavid Greenman 	} else {
6516f62314SDavid Greenman 		bp = bpa;
6626f9a767SRodney W. Grimes 	}
6726f9a767SRodney W. Grimes 
6816f62314SDavid Greenman 	/*
6916f62314SDavid Greenman 	 * get a copy of the kva from the physical buffer
7016f62314SDavid Greenman 	 */
7116f62314SDavid Greenman 	sa = bpa->b_data;
7226f9a767SRodney W. Grimes 	bp->b_proc = curproc;
7326f9a767SRodney W. Grimes 	bp->b_dev = dev;
7426f9a767SRodney W. Grimes 	error = bp->b_error = 0;
7526f9a767SRodney W. Grimes 
7626f9a767SRodney W. Grimes 	for(i=0;i<uio->uio_iovcnt;i++) {
7726f9a767SRodney W. Grimes 		while( uio->uio_iov[i].iov_len) {
7826f9a767SRodney W. Grimes 			vm_offset_t v, lastv, pa;
7926f9a767SRodney W. Grimes 			caddr_t adr;
8026f9a767SRodney W. Grimes 
8126f9a767SRodney W. Grimes 			bp->b_bcount = uio->uio_iov[i].iov_len;
82a481f200SDavid Greenman 			bp->b_bcount = minp( bp);
83a481f200SDavid Greenman 			if( minp != minphys)
84a481f200SDavid Greenman 				bp->b_bcount = minphys( bp);
8526f9a767SRodney W. Grimes 			bp->b_bufsize = bp->b_bcount;
8626f9a767SRodney W. Grimes 			bp->b_flags = B_BUSY | B_PHYS | B_CALL | bufflags;
8726f9a767SRodney W. Grimes 			bp->b_iodone = physwakeup;
8826f9a767SRodney W. Grimes 			bp->b_data = uio->uio_iov[i].iov_base;
8916f62314SDavid Greenman 			/*
9016f62314SDavid Greenman 			 * pass in the kva from the physical buffer
9116f62314SDavid Greenman 			 * for the temporary kernel mapping.
9216f62314SDavid Greenman 			 */
9316f62314SDavid Greenman 			bp->b_saveaddr = sa;
9426f9a767SRodney W. Grimes 			bp->b_blkno = btodb(uio->uio_offset);
9526f9a767SRodney W. Grimes 
9626f9a767SRodney W. Grimes 
9726f9a767SRodney W. Grimes 			if (rw && !useracc(bp->b_data, bp->b_bufsize, B_WRITE)) {
9826f9a767SRodney W. Grimes 				error = EFAULT;
9926f9a767SRodney W. Grimes 				goto doerror;
10026f9a767SRodney W. Grimes 			}
10126f9a767SRodney W. Grimes 			if (!rw && !useracc(bp->b_data, bp->b_bufsize, B_READ)) {
10226f9a767SRodney W. Grimes 				error = EFAULT;
10326f9a767SRodney W. Grimes 				goto doerror;
10426f9a767SRodney W. Grimes 			}
10526f9a767SRodney W. Grimes 
10626f9a767SRodney W. Grimes 			vmapbuf(bp);
10726f9a767SRodney W. Grimes 
10826f9a767SRodney W. Grimes 			/* perform transfer */
10926f9a767SRodney W. Grimes 			(*strategy)(bp);
11026f9a767SRodney W. Grimes 
11126f9a767SRodney W. Grimes 			spl = splbio();
11226f9a767SRodney W. Grimes 			while ((bp->b_flags & B_DONE) == 0)
11326f9a767SRodney W. Grimes 				tsleep((caddr_t)bp, PRIBIO, "physstr", 0);
11426f9a767SRodney W. Grimes 			splx(spl);
11526f9a767SRodney W. Grimes 
11626f9a767SRodney W. Grimes 			vunmapbuf(bp);
11726f9a767SRodney W. Grimes 
11826f9a767SRodney W. Grimes 			/*
11926f9a767SRodney W. Grimes 			 * update the uio data
12026f9a767SRodney W. Grimes 			 */
12126f9a767SRodney W. Grimes 			{
12226f9a767SRodney W. Grimes 				int iolen = bp->b_bcount - bp->b_resid;
1237d7bb69dSDavid Greenman 
1247d7bb69dSDavid Greenman 				if (iolen == 0 && !(bp->b_flags & B_ERROR))
1257d7bb69dSDavid Greenman 					goto doerror;	/* EOF */
12626f9a767SRodney W. Grimes 				uio->uio_iov[i].iov_len -= iolen;
12726f9a767SRodney W. Grimes 				uio->uio_iov[i].iov_base += iolen;
12826f9a767SRodney W. Grimes 				uio->uio_resid -= iolen;
12926f9a767SRodney W. Grimes 				uio->uio_offset += iolen;
13026f9a767SRodney W. Grimes 			}
13126f9a767SRodney W. Grimes 
13226f9a767SRodney W. Grimes 			/*
13326f9a767SRodney W. Grimes 			 * check for an error
13426f9a767SRodney W. Grimes 			 */
13526f9a767SRodney W. Grimes 			if( bp->b_flags & B_ERROR) {
13626f9a767SRodney W. Grimes 				error = bp->b_error;
13726f9a767SRodney W. Grimes 				goto doerror;
13826f9a767SRodney W. Grimes 			}
13926f9a767SRodney W. Grimes 		}
14026f9a767SRodney W. Grimes 	}
14126f9a767SRodney W. Grimes 
14226f9a767SRodney W. Grimes 
14326f9a767SRodney W. Grimes doerror:
14416f62314SDavid Greenman 	relpbuf(bpa);
14516f62314SDavid Greenman 	if (!bp_alloc) {
14626f9a767SRodney W. Grimes 		bp->b_flags &= ~(B_BUSY|B_PHYS);
14726f9a767SRodney W. Grimes 		if( bp->b_flags & B_WANTED) {
14826f9a767SRodney W. Grimes 			bp->b_flags &= ~B_WANTED;
14926f9a767SRodney W. Grimes 			wakeup((caddr_t)bp);
15026f9a767SRodney W. Grimes 		}
15126f9a767SRodney W. Grimes 	}
15226f9a767SRodney W. Grimes /*
15326f9a767SRodney W. Grimes  * allow the process to be swapped
15426f9a767SRodney W. Grimes  */
15526f9a767SRodney W. Grimes 	curproc->p_flag &= ~P_PHYSIO;
15626f9a767SRodney W. Grimes 
15726f9a767SRodney W. Grimes 	return (error);
158df8bae1dSRodney W. Grimes }
159df8bae1dSRodney W. Grimes 
160df8bae1dSRodney W. Grimes u_int
16126f9a767SRodney W. Grimes minphys(struct buf *bp)
162df8bae1dSRodney W. Grimes {
163df8bae1dSRodney W. Grimes 
16426f9a767SRodney W. Grimes 	if( bp->b_bcount > MAXBSIZE) {
16526f9a767SRodney W. Grimes 		bp->b_bcount = MAXBSIZE;
16626f9a767SRodney W. Grimes 	}
16726f9a767SRodney W. Grimes 	return bp->b_bcount;
168df8bae1dSRodney W. Grimes }
169df8bae1dSRodney W. Grimes 
17026f9a767SRodney W. Grimes int
17126f9a767SRodney W. Grimes rawread(dev_t dev, struct uio *uio)
172df8bae1dSRodney W. Grimes {
173df8bae1dSRodney W. Grimes 	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
17426f9a767SRodney W. Grimes 	    dev, 1, minphys, uio));
175df8bae1dSRodney W. Grimes }
176df8bae1dSRodney W. Grimes 
17726f9a767SRodney W. Grimes int
17826f9a767SRodney W. Grimes rawwrite(dev_t dev, struct uio *uio)
179df8bae1dSRodney W. Grimes {
180df8bae1dSRodney W. Grimes 	return (physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
18126f9a767SRodney W. Grimes 	    dev, 0, minphys, uio));
18226f9a767SRodney W. Grimes }
18326f9a767SRodney W. Grimes 
18426f9a767SRodney W. Grimes static void
18526f9a767SRodney W. Grimes physwakeup(bp)
18626f9a767SRodney W. Grimes 	struct buf *bp;
18726f9a767SRodney W. Grimes {
18826f9a767SRodney W. Grimes 	wakeup((caddr_t) bp);
18926f9a767SRodney W. Grimes 	bp->b_flags &= ~B_CALL;
190df8bae1dSRodney W. Grimes }
191