V10/lsys/md/cdiskstar.c
/*
* Star console floppy
* -- traces of multiple drives; this was derived from Nautilus.
* It is probably easier to leave the traces in for future need.
*/
#include "sys/param.h"
#include "sys/user.h"
#include "sys/buf.h"
#include "sys/conf.h"
/*
* interface to console driver
* this should really be in a header somewhere
*/
extern int *cniwrite(), *cniread();
extern int cniwait();
int cbsopen(), cbsread(), cbswrite();
struct cdevsw cbscdev = cdinit(cbsopen, nulldev, cbsread, cbswrite, nodev);
#define NDEVS 1
static char cbsid[NDEVS] = {
1, /* (0) floppy */
};
#define BSCMD 0x9 /* ID to write commands */
#define BSSTS 0x2 /* ID to read answers */
#define SECTOR 128
#define SECTRK 26
#define MAXBLK (77*SECTRK)
#define RCOM 0
#define WCOM 1
#define USHIFT 4
#define STSTS(s) ((s)&0200) /* status in status */
#define STOK 0
#define UNIT(d) ((d)&077) /* in case of silly 0100 bit */
static char cbsbusy, cbswant;
#define MAXRAW (4*SECTOR)
static struct buf cbsbuf;
static char cbsdat[MAXRAW];
struct buf *cbsmkbuf();
cbsopen(dev)
dev_t dev;
{
if (UNIT(minor(dev)) >= NDEVS)
u.u_error = ENXIO;
}
cbsread(dev)
dev_t dev;
{
register struct buf *bp;
if ((bp = cbsmkbuf(dev, B_READ)) == NULL)
return;
cbsdoio(bp, (daddr_t)(Ltol(u.u_offset)/SECTOR));
iowait(bp);
if (u.u_error == 0)
iomove(bp->b_un.b_addr, bp->b_bcount-bp->b_resid, B_READ);
cbsrelse(bp);
}
cbswrite(dev)
dev_t dev;
{
register struct buf *bp;
daddr_t sno;
if ((bp = cbsmkbuf(dev, B_WRITE)) == NULL)
return;
sno = Ltol(u.u_offset)/SECTOR;
iomove(bp->b_un.b_addr, bp->b_bcount, B_WRITE);
if (u.u_error) {
cbsrelse(bp);
return;
}
cbsdoio(bp, sno);
iowait(bp);
cbsrelse(bp);
}
struct buf *
cbsmkbuf(dev, rw)
dev_t dev;
int rw;
{
register struct buf *bp;
register int s;
if (u.u_count < SECTOR || (Ltol(u.u_offset) % SECTOR) != 0) {
u.u_error = ENXIO;
return (NULL);
}
bp = &cbsbuf;
s = spl6();
while (bp->b_flags & B_BUSY) {
bp->b_flags |= B_WANTED;
sleep((caddr_t)bp, PRIBIO);
}
bp->b_flags = B_BUSY | rw;
splx(s);
bp->b_bcount = min(u.u_count, MAXRAW);
bp->b_un.b_addr = cbsdat;
bp->b_dev = dev;
/* b_blkno unused by any code we'll call */
return (bp);
}
cbsrelse(bp)
register struct buf *bp;
{
if (bp->b_flags & B_WANTED)
wakeup((caddr_t)bp);
bp->b_flags &=~ (B_WANTED|B_BUSY);
}
cbsdoio(bp, sno)
struct buf *bp;
daddr_t sno;
{
int s;
if (sno >= MAXBLK) {
bp->b_flags |= B_ERROR;
iodone(bp);
return;
}
s = spl6();
while (cbsbusy) {
cbswant++;
sleep(&cbsbusy);
}
cbsbusy++;
splx(s);
if (bp->b_flags & B_READ)
cbsrd(bp, sno);
else
cbswr(bp, sno);
if (cbswant) {
cbswant = 0;
wakeup(&cbsbusy);
}
cbsbusy = 0;
}
cbsrd(bp, sno)
register struct buf *bp;
daddr_t sno;
{
static char cmd[2];
static unsigned char sts;
register int unit;
register char *buf;
register int *pst, *pdt;
unit = UNIT(minor(bp->b_dev));
bp->b_resid = bp->b_bcount;
buf = bp->b_un.b_addr;
while (bp->b_resid >= SECTOR) {
cmd[0] = RCOM|(unit<<USHIFT);
pst = cniwrite(BSCMD, cmd, 1);
if (cniwait(pst, 5)) {
bp->b_flags |= B_ERROR;
break;
}
cmd[0] = (sno%SECTRK) + 1;
cmd[1] = sno / SECTRK;
pst = cniread(BSSTS, &sts, 1);
pdt = cniread(cbsid[unit], buf, SECTOR);
cniwrite(cbsid[unit], cmd, 2);
if (cniwait(pst, 5) || STSTS(sts) != STOK) {
*pdt = 0;
if (bp->b_resid != bp->b_bcount)
bp->b_flags |= B_ERROR;
break;
}
if (cniwait(pdt, 5)) {
if (bp->b_resid != bp->b_bcount)
bp->b_flags |= B_ERROR;
break;
}
sno++;
buf += SECTOR;
bp->b_resid -= SECTOR;
}
iodone(bp);
}
cbswr(bp, sno)
register struct buf *bp;
daddr_t sno;
{
static char cmd[2];
static unsigned char sts;
register int unit;
register char *buf;
register int *pst, *pdt;
unit = UNIT(minor(bp->b_dev));
bp->b_resid = bp->b_bcount;
buf = bp->b_un.b_addr;
while (bp->b_resid >= SECTOR) {
cmd[0] = WCOM|(unit<<USHIFT);
pst = cniwrite(BSCMD, cmd, 1);
if (cniwait(pst, 5)) {
bp->b_flags |= B_ERROR;
break;
}
cmd[0] = (sno%SECTRK) + 1;
cmd[1] = sno / SECTRK;
pst = cniread(BSSTS, &sts, 1);
pdt = cniwrite(cbsid[unit], cmd, 2);
if (cniwait(pdt, 5)) {
*pst = 0;
bp->b_flags |= B_ERROR;
break;
}
pdt = cniwrite(cbsid[unit], buf, SECTOR);
if (cniwait(pst, 5) || STSTS(sts) != STOK) {
*pdt = 0;
if (bp->b_resid != bp->b_bcount)
bp->b_flags |= B_ERROR;
break;
}
if (cniwait(pdt, 1)) {
if (bp->b_resid != bp->b_bcount)
bp->b_flags |= B_ERROR;
break;
}
sno++;
buf += SECTOR;
bp->b_resid -= SECTOR;
}
iodone(bp);
}