+#
+/*
+ * 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;
+}