V5/usr/sys/dmr/bio.c
#
/*
* Copyright 1973 Bell Telephone Laboratories Inc
*/
#include "../param.h"
#include "../user.h"
#include "../buf.h"
#include "../conf.h"
#include "../systm.h"
#include "../proc.h"
#include "../seg.h"
char buffers[NBUF][514];
struct buf swbuf;
struct { int int;};
#define PS 0177776
int tmtab;
int raflag 1;
bread(dev, blkno)
{
register struct buf *rbp;
rbp = getblk(dev, blkno);
if (rbp->b_flags&B_DONE)
return(rbp);
rbp->b_flags =| B_READ;
rbp->b_wcount = -256;
(*bdevsw[dev.d_major].d_strategy)(rbp);
iowait(rbp);
return(rbp);
}
breada(adev, blkno, rablkno)
{
register struct buf *rbp, *rabp;
register int dev;
dev = adev;
rbp = 0;
if (!incore(dev, blkno)) {
rbp = getblk(dev, blkno);
if ((rbp->b_flags&B_DONE) == 0) {
rbp->b_flags =| B_READ;
rbp->b_wcount = -256;
(*bdevsw[adev.d_major].d_strategy)(rbp);
}
}
if (rablkno && !incore(dev, rablkno) && raflag) {
rabp = getblk(dev, rablkno);
if (rabp->b_flags & B_DONE)
brelse(rabp);
else {
rabp->b_flags =| B_READ|B_ASYNC;
rabp->b_wcount = -256;
(*bdevsw[adev.d_major].d_strategy)(rabp);
}
}
if (rbp==0)
return(bread(dev, blkno));
iowait(rbp);
return(rbp);
}
bwrite(bp)
struct buf *bp;
{
register struct buf *rbp;
register flag;
rbp = bp;
flag = rbp->b_flags;
rbp->b_flags =& ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
rbp->b_wcount = -256;
(*bdevsw[rbp->b_dev.d_major].d_strategy)(rbp);
if ((flag&B_ASYNC) == 0) {
iowait(rbp);
brelse(rbp);
} else if ((flag&B_DELWRI)==0)
geterror(rbp);
}
bdwrite(bp)
struct buf *bp;
{
register struct buf *rbp;
rbp = bp;
if (bdevsw[rbp->b_dev.d_major].d_tab == &tmtab)
bawrite(rbp);
else {
rbp->b_flags =| B_DELWRI | B_DONE;
brelse(rbp);
}
}
bawrite(bp)
struct buf *bp;
{
register struct buf *rbp;
rbp = bp;
rbp->b_flags =| B_ASYNC;
bwrite(rbp);
}
brelse(bp)
struct buf *bp;
{
register struct buf *rbp, **backp;
register int sps;
rbp = bp;
if (rbp->b_flags&B_WANTED)
wakeup(rbp);
if (bfreelist.b_flags&B_WANTED) {
bfreelist.b_flags =& ~B_WANTED;
wakeup(&bfreelist);
}
if (rbp->b_flags&B_ERROR)
rbp->b_dev.d_minor = -1; /* no assoc. on error */
backp = &bfreelist.av_back;
sps = PS->int;
spl6();
rbp->b_flags =& ~(B_WANTED|B_BUSY|B_ASYNC);
(*backp)->av_forw = rbp;
rbp->av_back = *backp;
*backp = rbp;
rbp->av_forw = &bfreelist;
PS->int = sps;
}
incore(adev, blkno)
{
register int dev;
register struct buf *bp;
register struct devtab *dp;
dev = adev;
dp = bdevsw[adev.d_major].d_tab;
for (bp=dp->b_forw; bp != dp; bp = bp->b_forw)
if (bp->b_blkno==blkno && bp->b_dev==dev)
return(bp);
return(0);
}
getblk(dev, blkno)
{
register struct buf *bp;
register struct devtab *dp;
extern lbolt;
if(dev.d_major >= nblkdev)
panic("blkdev");
loop:
if (dev < 0)
dp = &bfreelist;
else {
dp = bdevsw[dev.d_major].d_tab;
for (bp=dp->b_forw; bp != dp; bp = bp->b_forw) {
if (bp->b_blkno!=blkno || bp->b_dev!=dev)
continue;
spl6();
if (bp->b_flags&B_BUSY) {
bp->b_flags =| B_WANTED;
sleep(bp, PRIBIO);
spl0();
goto loop;
}
spl0();
notavail(bp);
return(bp);
}
}
spl6();
if (bfreelist.av_forw == &bfreelist) {
bfreelist.b_flags =| B_WANTED;
sleep(&bfreelist, PRIBIO);
spl0();
goto loop;
}
spl0();
notavail(bp = bfreelist.av_forw);
if (bp->b_flags & B_DELWRI) {
bp->b_flags =| B_ASYNC;
bwrite(bp);
goto loop;
}
bp->b_flags = B_BUSY | B_RELOC;
bp->b_back->b_forw = bp->b_forw;
bp->b_forw->b_back = bp->b_back;
bp->b_forw = dp->b_forw;
bp->b_back = dp;
dp->b_forw->b_back = bp;
dp->b_forw = bp;
bp->b_dev = dev;
bp->b_blkno = blkno;
return(bp);
}
iowait(bp)
struct buf *bp;
{
register struct buf *rbp;
rbp = bp;
spl6();
while ((rbp->b_flags&B_DONE)==0)
sleep(rbp, PRIBIO);
spl0();
geterror(rbp);
}
notavail(bp)
struct buf *bp;
{
register struct buf *rbp;
register int sps;
rbp = bp;
sps = PS->int;
spl6();
rbp->av_back->av_forw = rbp->av_forw;
rbp->av_forw->av_back = rbp->av_back;
rbp->b_flags =| B_BUSY;
PS->int = sps;
}
iodone(bp)
struct buf *bp;
{
register struct buf *rbp;
rbp = bp;
rbp->b_flags =| B_DONE;
if (rbp->b_flags&B_ASYNC)
brelse(rbp);
else {
rbp->b_flags =& ~B_WANTED;
wakeup(rbp);
}
}
clrbuf(bp)
int *bp;
{
register *p;
register c;
p = bp->b_addr;
c = 256;
do
*p++ = 0;
while (--c);
}
binit()
{
register struct buf *bp;
register struct devtab *dp;
register int i;
struct bdevsw *bdp;
bfreelist.b_forw = bfreelist.b_back =
bfreelist.av_forw = bfreelist.av_back = &bfreelist;
for (i=0; i<NBUF; i++) {
bp = &buf[i];
bp->b_dev = -1;
bp->b_addr = buffers[i];
bp->b_back = &bfreelist;
bp->b_forw = bfreelist.b_forw;
bfreelist.b_forw->b_back = bp;
bfreelist.b_forw = bp;
bp->b_flags = B_BUSY;
brelse(bp);
}
i = 0;
for (bdp = bdevsw; bdp->d_open; bdp++) {
dp = bdp->d_tab;
dp->b_forw = dp;
dp->b_back = dp;
i++;
}
nblkdev = i;
}
/*
* Device start routine for disks
*/
#define IENABLE 0100
#define WCOM 02
#define RCOM 04
#define GO 01
devstart(bp, devloc, devblk, hbcom)
struct buf *bp;
int *devloc;
{
register int *dp;
register struct buf *rbp;
register int com;
dp = devloc;
rbp = bp;
*dp = devblk; /* block address */
*--dp = rbp->b_addr; /* buffer address */
*--dp = rbp->b_wcount; /* word count */
com = (hbcom<<8) | IENABLE | GO | rbp->b_flags&B_XMEM;
if (rbp->b_flags&B_READ) /* command + x-mem */
com =| RCOM;
else
com =| WCOM;
*--dp = com;
}
/*
* swap I/O
*/
swap(blkno, coreaddr, count, rdflg)
{
register int *fp;
fp = &swbuf.b_flags;
spl6();
while (*fp&B_BUSY) {
*fp =| B_WANTED;
sleep(fp, PSWP);
}
*fp = B_BUSY | rdflg | (coreaddr>>6)&B_XMEM;
swbuf.b_dev = swapdev;
swbuf.b_wcount = - (count<<5); /* 32 w/block */
swbuf.b_blkno = blkno;
swbuf.b_addr = coreaddr<<6; /* 64 b/block */
(*bdevsw[swapdev>>8].d_strategy)(&swbuf);
spl6();
while((*fp&B_DONE)==0)
sleep(fp, PSWP);
if (*fp&B_WANTED)
wakeup(fp);
spl0();
*fp =& ~(B_BUSY|B_WANTED);
return(*fp&B_ERROR);
}
/*
* make sure all write-behind blocks
* on dev (or NODEV for all)
* are flushed out.
*/
bflush(dev)
{
register struct buf *bp;
loop:
spl6();
for (bp = bfreelist.av_forw; bp != &bfreelist; bp = bp->av_forw) {
if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) {
bp->b_flags =| B_ASYNC;
notavail(bp);
bwrite(bp);
goto loop;
}
}
spl0();
}
physio(strat, abp, dev, rw)
struct buf *abp;
int (*strat)();
{
register struct buf *bp;
register char *base;
register int nb;
int ts;
bp = abp;
base = u.u_base;
if (base&01 || u.u_count&01 || base>=base+u.u_count)
goto bad;
ts = (u.u_tsize+127) & ~0177;
nb = (base>>6) & 01777;
if (nb < ts)
goto bad;
if ((((base+u.u_count)>>6)&01777) >= ts+u.u_dsize
&& nb < 1024-u.u_ssize)
goto bad;
spl6();
while (bp->b_flags&B_BUSY) {
bp->b_flags =| B_WANTED;
sleep(bp, PRIBIO);
}
bp->b_flags = B_BUSY | rw;
bp->b_dev = dev;
bp->b_addr = base&077;
base = UISA->r[nb>>7] + (nb&0177);
bp->b_flags =| (base>>6) & B_XMEM;
bp->b_blkno = lshift(u.u_offset, -9);
bp->b_addr =+ base<<6;
bp->b_wcount = -((u.u_count>>1) & 077777);
bp->b_error = 0;
u.u_procp->p_flag =| SLOCK;
(*strat)(bp);
spl6();
while ((bp->b_flags&B_DONE) == 0)
sleep(bp, PRIBIO);
u.u_procp->p_flag =& ~SLOCK;
if (bp->b_flags&B_WANTED)
wakeup(bp);
spl0();
bp->b_flags =& ~(B_BUSY|B_WANTED);
u.u_count = (-bp->b_resid)<<1;
geterror(bp);
return;
bad:
u.u_error = EFAULT;
}
geterror(abp)
struct buf *abp;
{
register struct buf *bp;
bp = abp;
if (bp->b_flags&B_ERROR)
if ((u.u_error = bp->b_error)==0)
u.u_error = EIO;
}