V8/usr/sys/dev/sn.c
#define BSD41
#define VAXONE
#define TIMEOUT
#ifdef MARVIN
#define TXDRIVER
#endif
#ifdef CANTOR
#define TXDRIVER
#endif
#ifdef HILBERT
#define TXDRIVER
#endif
#ifdef DAISY
#define TXDRIVER
#endif
#ifdef USG5
#define NSN 1
#else
#include "sn.h"
#endif
#if NSN > 0
#ifdef BSD41
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/buf.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/pte.h"
#include "../h/map.h"
#include "../h/vm.h"
#include "../h/dk.h"
#include "../h/cmap.h"
#include "../h/ubareg.h"
#include "../h/ubavar.h"
#include "../h/cpu.h"
#include "../h/proc.h"
#include "../h/snet.h"
#include "../h/packet.h"
#include "../h/channel.h"
#include "../h/status.h"
#endif
#ifdef SNDEBUG
int sndebug = 1;
#else
int sndebug = 0;
#endif
/* flags for status */
#define INPUT 1
#define OUTPUT 2
#define min(x,y) ((x) < (y) ? (x) : (y))
#define swab(x) (unsigned short)((((x)>>8)&0xff) | ((x) << 8))
#define SNPRI 28
#define CHKINIT 0xbf37
struct device {
short drcs;
short drout;
short drin;
};
/* Command and Status word */
#define CSR0 0x1
#define CSR1 0x2
#define RIE 0x20
#define TIE 0x40
#define TEMPTY 0x80
#define RFULL 0x8000
/*
* CSR1 CSR0
* 0 0 Write Data
* 0 1 Write EOP
* 1 0 Write Command
* 1 1 Read Status
*/
#define DATA_MODE (RIE)
#define EOP_MODE (CSR0 | RIE)
#define CMD_MODE (CSR1 | RIE)
#define STATUS_MODE (CSR0 | CSR1 | RIE)
/* Command word format
*
* +-----------------------------------------------+
* | |B |R |A | | | |
* | |C |S |B | DID | | FCN |
* | |T |T |T | | | |
* +-----------------------------------------------+
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
*/
/* Function codes */
#define NOP 0x0
#define BOARD_RESET 0x5
#define MASTER_CLEAR 0x6
#define ABORT(did) (0x1000 | (did))
#define RESET(did) (0x2000 | (did))
#define BROAD_CAST(did) (0x4000 | (did))
/* SNET status word bits
*
* +-----------------------------------------------+
* | |E |S |I |O | | |
* | |O |N |B |B | | |
* | |P |K |E |E | | |
* +-----------------------------------------------+
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
*/
#define OUTBUF_E 0x4
#define INBUF_E 0x8
#define SNACK 0x10 /* transmitter error */
#define EOP 0x20 /* we have read and EOP frame */
static int sn_multiplex;
struct openwait sn_openwait[NUMDEV];
struct openwait *sn_owhead, *sn_owtail;
#define SNFILE(dev) (minor(dev) & 0x3f)
#define SNUNIT(dev) ((minor(dev) & 0xc0) >> 6)
struct chdat sn_chans[NUMLCH];
#define MAXMSGLEN (512+8)
struct sn_buffers {
short inbuf[MAXMSGLEN];
short outbuf[MAXMSGLEN];
} sn_buffers[NUMLCH];
#define NOPDID -1
#ifdef TIMEOUT
#define CKFUZZ 4 /* number of timeouts we wait for a response */
#ifdef USG5
#define CKTICKS (HZ/4) /* number of ticks per timeout */
#else
#define CKTICKS (hz/4) /* number of ticks per timeout */
#endif
int sn_state;
#define OPEN 1 /* set if at least one sn? is open */
#define TIMER 2 /* set if at timer is running */
int cktimchk();
int sn_opncnt;
#endif TIMEOUT
struct snmach snmach[NUMDEV] = {
{ 1, 255 },
{ 2, 254 },
{ 3, 253 },
{ 4, 252 },
{ 5, 251 },
{ 6, 250 },
{ 7, 249 },
{ 8, 248 } };
int sn_once;
#ifdef BSD42
#define RETURN(x) {return(x);}
#define ARGS(x) args->x
#else
#define RETURN(x) {u.u_error = x; return;}
#define ARGS(x) args.x
#endif
#ifdef USG5
extern struct sninfo sn_sninfo[];
extern int sn_cnt;
extern struct device *sn_addr[];
#else
struct sninfo sn_sninfo[NSN];
int snprobe(), snattach();
struct uba_device *sndinfo[NSN];
u_short snstd[] = {0};
struct uba_driver sndriver =
{ snprobe, 0, snattach, 0, snstd, "sn", sndinfo};
snprobe(reg)
caddr_t reg;
{
register int br, cvec; /* value result */
register struct device *snaddr = (struct device *)reg;
br = 0x15;
#ifdef VAXONE
cvec = 0510;
#else
#ifdef CANTOR
if (((int)snaddr & 017777) == 007770)
cvec = 0504;
if (((int)snaddr & 017777) == 007750)
cvec = 0464;
#else
cvec = 0504;
#endif
#endif
#ifdef BSD41
return(1);
#endif
#ifdef BSD42
return(sizeof(struct device));
#endif
}
/*ARGSUSED*/
snattach(ui)
register struct uba_device *ui;
{
}
#endif
snopen(dev, rw)
dev_t dev;
int rw;
{
register struct device *draddr;
#ifndef USG5
struct uba_device *ui;
#endif
register struct sninfo *sninfop;
int mdev = SNFILE(dev);
int unit = SNUNIT(dev);
if( sndebug )
printf("snopen(%x,%x)\n", dev, rw);
#ifdef USG5
if ( mdev > NUMDEV || unit >= sn_cnt) {
RETURN ( ENXIO );
}
draddr = sn_addr[unit];
#else
if (mdev > NUMDEV || unit >= NSN ||
(ui = sndinfo[unit]) == 0 || ui->ui_alive == 0) {
RETURN ( ENXIO );
}
draddr = (struct device *)ui->ui_addr;
#endif
if ( sn_once == 0 ) {
struct chdat *cp = sn_chans;
sn_once++;
for( ; cp<&sn_chans[NUMLCH]; cp++) {
cp->lchnum = -1;
cp->dlchnum = -1;
}
sn_owhead = sn_owtail = sn_openwait;
}
sninfop = &sn_sninfo[unit];
spl6();
if (sninfop->sndevlock[mdev]++ != 0) {
spl0();
RETURN ( EBUSY );
}
#ifdef TIMEOUT
sn_opncnt++;
sn_state |= OPEN;
if ((sn_state & TIMER) == 0) {
sn_state |= TIMER;
timeout(cktimchk, (caddr_t)0, CKTICKS);
}
#endif TIMEOUT
if( sninfop->snlock++ == 0 ) {
#ifdef TXDRIVER
{
extern struct txinfo tx_sninfo[];
if (tx_sninfo[unit].snlock != 0) {
spl0();
return;
}
}
#endif
draddr->drcs = CMD_MODE;
draddr->drout = 0;
draddr->drout = BOARD_RESET;
draddr->drout = 0;
draddr->drcs = DATA_MODE;
}
spl0();
return(0);
}
snclose(dev)
{
register struct chdat *cp;
#ifndef USG5
struct uba_device *ui;
#endif
register struct sninfo *sninfop;
register struct device *draddr;
int mdev = SNFILE(dev);
int unit = SNUNIT(dev);
int resetmachno;
struct openwait *curtail;
if( sndebug )
printf("snclose(%x)\n", dev);
#ifdef USG5
if ( unit >= sn_cnt) {
RETURN ( ENXIO );
}
draddr = sn_addr[unit];
#else
if ( unit >= NSN) {
RETURN ( ENXIO );
}
ui = sndinfo[unit];
draddr = (struct device *)ui->ui_addr;
#endif
sninfop = &sn_sninfo[unit];
spl6();
if( sninfop->snlock == 0 || mdev > NUMDEV
|| sninfop->sndevlock[mdev] == 0 ) {
spl0();
RETURN ( ENXIO );
}
resetmachno = -1;
for(cp=sninfop->snlink[mdev]; cp; cp=cp->link) {
if (cp->pdid == NOPDID)
resetmachno = cp->machno;
chclose(cp);
}
if (resetmachno != -1) {
for(cp=sn_chans; cp < &sn_chans[NUMLCH]; cp++) {
if (cp->pdid == NOPDID && cp->machno == resetmachno)
goto noreset;
}
draddr->drcs = CMD_MODE;
draddr->drout = RESET(resetmachno << 8);
draddr->drcs = EOP_MODE;
draddr->drout = 0;
draddr->drcs = DATA_MODE;
}
noreset:
for (curtail = sn_owtail; curtail != sn_owhead;
curtail = ownext(curtail)) {
if (curtail->pid == u.u_procp->p_pid) {
curtail->pid = 0;
goto nowakeup;
}
}
while (sn_owtail != sn_owhead) {
curtail = sn_owtail;
sn_owtail = ownext(sn_owtail);
if (curtail->pid) {
wakeup(curtail);
break;
}
}
nowakeup:
sninfop->snlink[mdev] = 0;
sninfop->sndevlock[mdev] = 0;
#ifdef TIMEOUT
if (--sn_opncnt <= 0) {
sn_state &= ~OPEN;
sn_opncnt = 0;
}
#endif TIMEOUT
if (--sninfop->snlock == 0 ) {
#ifdef TXDRIVER
{
if (tx_sninfo[unit].snlock != 0)
return;
}
#endif
draddr->drcs &= ~RIE;
}
spl0();
return(0);
}
static short ratshole[MAXMSGLEN];
static struct chdat ratschan;
#ifdef USG5
snintr(unit)
#else
snrint(unit)
#endif
int unit;
{
register struct chdat *cp;
register short *sp, *dp;
register int i;
register struct sninfo *sninfop;
register struct device *draddr;
unsigned short chksum, xchk;
short len;
unsigned short chan;
short *osp;
#ifndef USG5
struct uba_device *ui;
#endif
#ifdef USG5
draddr = sn_addr[unit];
#else
ui = sndinfo[unit];
draddr = (struct device *)ui->ui_addr;
#endif
dp = &draddr->drin;
sninfop = &sn_sninfo[unit];
sninfop->snrcnt++;
loop:
chksum = CHKINIT;
chan = *dp;
#ifdef TXDRIVER
/* unusual process numbers go to tx driver */
if ((chan & 0xff) <= 200 || ((unsigned int)chan) >= 0x2000 ) {
txintrmt(unit, chan);
goto getstatus;
}
#endif
chksum ^= chan;
chan = swab(chan);
len = *dp;
chksum ^= len;
len = swab(len);
if( len > MAXMSGLEN ) {
sninfop->snnbadlen++;
goto getstatus;
}
sninfop->sninbytes += len+4;
for(cp=sn_chans; cp < &sn_chans[NUMLCH]; cp++)
if( cp->xchan == chan && cp->snunit == unit ) {
if( cp->input.done == 0 && len <= cp->input.len )
osp = sp = cp->input.buf;
else
osp = sp = ratshole;
goto found;
}
osp = sp = ratshole;
cp = &ratschan;
sninfop->snnnolc++;
found:
for(i=len; i>0; i-=8) {
switch( i ) {
default:
*sp = *dp;
chksum ^= *sp++;
case 7:
*sp = *dp;
chksum ^= *sp++;
case 6:
*sp = *dp;
chksum ^= *sp++;
case 5:
*sp = *dp;
chksum ^= *sp++;
case 4:
*sp = *dp;
chksum ^= *sp++;
case 3:
*sp = *dp;
chksum ^= *sp++;
case 2:
*sp = *dp;
chksum ^= *sp++;
case 1:
*sp = *dp;
chksum ^= *sp++;
}
}
if( (i = ((len < 0 ? 0 : len) + 3)&0xf) != 0 ) {
for(i^=0xf; i-->=0; )
chksum ^= *dp;
}
if( chksum != (xchk = *dp) ) {
sninfop->snnchksum++;
if( sndebug ) {
short *usp = osp;
int x = len;
printf("snchksum (%x, %x):", chan, len);
for(; --x>=0; )
printf(" %x", *usp++);
printf(" %x (%x)\n", xchk, chksum);
}
} else if( len > 0 ) {
if( osp == ratshole ) {
cp->flags |= SENTRNR;
snxstart(unit, cp, RNR);
sninfop->snsrnr++;
} else {
sninfop->snndata++;
cp->input.done = 1;
cp->input.len = len;
snxstart(unit, cp, ACK);
sninfop->snsack++;
wakeup((caddr_t)cp->input.buf);
if( cp->flags&MULTIPLEX )
wakeup((caddr_t)&sn_multiplex);
}
} else {
switch( len ) {
case ACK:
sninfop->snnack++;
cp->flags &= ~SENTDATA;
cp->output.done = 1;
wakeup((caddr_t)cp->output.buf);
break;
case RDY:
sninfop->snnrdy++;
snxstart(unit, cp, RACK);
if( cp->output.done == 0 && cp->output.len > 0 ) {
snxstart(unit, cp, DATA);
sninfop->snrout++;
}
break;
case RNR:
sninfop->snnrnr++;
cp->flags &= ~SENTDATA;
break;
case RACK:
sninfop->snnrack++;
cp->flags &= ~SENTRDY;
break;
default:
printf("snrint: unit %d, bad type %d\n", unit, len);
break;
}
}
getstatus:
draddr->drcs = STATUS_MODE;
i = *dp;
draddr->drcs = DATA_MODE;
if ((i&INBUF_E) == 0) {
sninfop->sninloop++;
goto loop;
}
}
snxstart(unit, cp, type)
int unit;
register struct chdat *cp;
int type;
{
register short *sp, *dp;
register struct sninfo *sninfop;
register struct device *draddr;
register int i;
unsigned short chksum;
#ifndef USG5
struct uba_device *ui;
#endif
int len, numretry;
#ifdef USG5
draddr = sn_addr[unit];
#else
ui = sndinfo[unit];
draddr = (struct device *)ui->ui_addr;
#endif
dp = &draddr->drout;
sninfop = &sn_sninfo[unit];
if( type == DATA ) {
len = cp->output.len;
sninfop->snoutbytes += len+4;
} else {
len = type;
sninfop->snoutbytes += 4;
}
draddr->drcs = STATUS_MODE;
i = draddr->drin;
if ( (i&OUTBUF_E) == 0 ) {
sninfop->snoutfull++;
do {
i = draddr->drin;
sninfop->sncntoutfull++;
} while( (i&OUTBUF_E) == 0 );
}
numretry = 0;
sninfop->snxcnt++;
retry:
sp = cp->output.buf;
chksum = CHKINIT;
if (cp->pdid == NOPDID) {
draddr->drcs = CMD_MODE;
*dp = cp->machno<<8;
draddr->drcs = DATA_MODE;
*dp = i = swab(cp->dlchnum);
} else {
draddr->drcs = CMD_MODE;
*dp = cp->pdid<<8;
draddr->drcs = DATA_MODE;
*dp = i = (cp->dlchnum<<8) | cp->machno;
}
chksum ^= (unsigned short)i;
*dp = i = swab(len);
chksum ^= (unsigned short)i;
for( i=len; i>0; i-=8 ) {
switch( i ) {
default:
chksum ^= *sp;
*dp = *sp++;
case 7:
chksum ^= *sp;
*dp = *sp++;
case 6:
chksum ^= *sp;
*dp = *sp++;
case 5:
chksum ^= *sp;
*dp = *sp++;
case 4:
chksum ^= *sp;
*dp = *sp++;
case 3:
chksum ^= *sp;
*dp = *sp++;
case 2:
chksum ^= *sp;
*dp = *sp++;
case 1:
chksum ^= *sp;
*dp = *sp++;
}
}
if( (i = ((len < 0 ? 0 : len) + 3)&0xf) != 0 ) {
for(i^=0xf; i-->=0; )
*dp = 0;
}
draddr->drcs = EOP_MODE;
*dp = chksum;
draddr->drcs = STATUS_MODE;
i = draddr->drin;
draddr->drcs = DATA_MODE;
if( i&SNACK ) {
sninfop->snsnack++;
if( ++numretry < 100 )
goto retry;
sninfop->snlost++;
}
cp->ckticks = CKFUZZ;
if( type == DATA ) {
cp->flags |= SENTDATA;
}
}
snioctl(dev, cmd, addr, flag)
caddr_t addr;
dev_t dev;
{
register struct chdat *cp;
register struct reqinfo *rp;
register struct sninfo *sninfop;
register struct bufinfo *bp;
register struct chdat *dp;
struct status status;
int i;
struct status *ustatus;
char *usaddr;
int ulen;
int error;
int mdev = SNFILE(dev);
int unit = SNUNIT(dev);
#ifdef USG5
if ( unit >= sn_cnt) {
RETURN ( ENXIO );
}
#else
if ( unit >= NSN) {
RETURN ( ENXIO );
}
#endif
sninfop = &sn_sninfo[unit];
switch( cmd ) {
case NIOOPEN: {
#ifdef BSD42
struct oargs *args = (struct oargs *)addr;
#else
struct oargs args;
if (copyin(addr, (caddr_t)&args, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
spl6();
for(cp=sn_chans; cp<&sn_chans[NUMLCH]; cp++)
if( cp->lchnum == -1 && cp->dlchnum == -1 )
break;
if( cp >= &sn_chans[NUMLCH] ) {
spl0();
RETURN( ENFILE );
}
for(dp=sn_chans; dp<&sn_chans[NUMLCH]; dp++)
if( dp->lchnum != -1 && dp->lmachno == ARGS(lmachno)
&& dp->lchnum == ARGS(lchno)
&& dp->snunit == unit ) {
spl0();
RETURN( EEXIST );
}
cp->lchnum = ARGS(lchno);
cp->dlchnum = ARGS(dlchno);
spl0();
cp->lmachno = ARGS(lmachno);
cp->machno = ARGS(dmachno);
cp->xchan = (cp->lmachno<<8)|cp->lchnum;
cp->snunit = unit;
cp->pdid = NOPDID;
bp = &cp->input;
i = cp-sn_chans;
bp->buf = sn_buffers[i].inbuf;
bp->len = MAXMSGLEN;
bp->done = 0;
bp = &cp->output;
bp->buf = sn_buffers[i].outbuf;
bp->len = bp->done = 0;
cp->flags = 0;
cp->link = sninfop->snlink[mdev];
sninfop->snlink[mdev] = cp;
return(0);
}
case NIOXOPEN: {
struct snmach *snmachp;
struct openwait *nexthead, *thishead;
#ifdef BSD42
struct oargs *args = (struct oargs *)addr;
#else
struct oargs args;
if (copyin(addr, (caddr_t)&args, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
for (;;) {
for (snmachp = &snmach[0];
snmachp < &snmach[NUMDEV] &&
snmachp->machno;
snmachp++) {
spl6();
for (cp=sn_chans; cp<&sn_chans[NUMLCH]; cp++)
if( cp->lchnum == -1 &&
cp->dlchnum == -1 )
break;
if( cp >= &sn_chans[NUMLCH] ) {
goto xopensleep;
}
for(dp=sn_chans; dp<&sn_chans[NUMLCH]; dp++) {
if( dp->lchnum != -1
&& dp->lmachno == snmachp->lmachno
&& dp->lchnum == ARGS(lchno)
&& dp->snunit == unit ) {
/* Channel already in use */
break;
}
}
if( dp >= &sn_chans[NUMLCH] )
goto okmachp;
spl0();
}
xopensleep:
nexthead = ownext(sn_owhead);
if (nexthead == sn_owtail) {
RETURN ( ENXIO );
}
thishead = sn_owhead;
thishead->pid = u.u_procp->p_pid;
sn_owhead = nexthead;
sleep((caddr_t)thishead, SNPRI);
}
okmachp:
cp->lchnum = ARGS(lchno);
cp->lmachno = snmachp->lmachno;
spl0();
cp->dlchnum = ARGS(dlchno);
cp->machno = snmachp->machno;
cp->xchan = (cp->lmachno<<8)|cp->lchnum;
cp->snunit = unit;
cp->pdid = NOPDID;
bp = &cp->input;
i = cp-sn_chans;
bp->buf = sn_buffers[i].inbuf;
bp->len = MAXMSGLEN;
bp->done = 0;
bp = &cp->output;
bp->buf = sn_buffers[i].outbuf;
bp->len = bp->done = 0;
cp->flags = 0;
cp->link = sninfop->snlink[mdev];
sninfop->snlink[mdev] = cp;
ARGS(lmachno) = snmachp->lmachno;
ARGS(dmachno) = snmachp->machno;
#ifndef BSD42
if (copyout((caddr_t)&args, addr, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
return(0);
}
case NIOPOPEN: {
#ifdef BSD42
struct voargs *args = (struct voargs *)addr;
#else
struct voargs args;
if (copyin(addr, (caddr_t)&args, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
spl6();
for(cp=sn_chans; cp<&sn_chans[NUMLCH]; cp++)
if( cp->lchnum == -1 && cp->dlchnum == -1 )
break;
if( cp >= &sn_chans[NUMLCH] ) {
spl0();
RETURN( ENFILE );
}
for(dp=sn_chans; dp<&sn_chans[NUMLCH]; dp++)
if( dp->lchnum != -1 && dp->lmachno == ARGS(lmachno)
&& dp->lchnum == ARGS(lchno)
&& dp->snunit == unit ) {
spl0();
RETURN( EEXIST );
}
cp->lchnum = ARGS(lchno);
cp->lmachno = ARGS(lmachno);
spl0();
cp->dlchnum = ARGS(dlchno);
cp->machno = ARGS(dmachno);
cp->xchan = (cp->lmachno<<8)|cp->lchnum;
cp->snunit = unit;
cp->pdid = ARGS(pdid);
bp = &cp->input;
i = cp-sn_chans;
bp->buf = sn_buffers[i].inbuf;
bp->len = MAXMSGLEN;
bp->done = 0;
bp = &cp->output;
bp->buf = sn_buffers[i].outbuf;
bp->len = bp->done = 0;
cp->flags = 0;
cp->link = sninfop->snlink[mdev];
sninfop->snlink[mdev] = cp;
return(0);
}
case NIOCLOSE: {
#ifdef BSD42
struct cargs *args = (struct cargs *)addr;
#else
struct cargs args;
if (copyin(addr, (caddr_t)&args, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
for(cp=sninfop->snlink[mdev], dp=0; cp; dp=cp, cp=cp->link)
if( cp->lmachno == ARGS(lmachno)
&& cp->lchnum == ARGS(lchno) ) {
/* TIMING !!! */
if( dp )
dp->link = cp->link;
else
sninfop->snlink[mdev] = cp->link;
chclose(cp);
return(0);
}
RETURN( EBADF );
}
case NIOGET:
case NIOPUT:
{
#ifdef BSD42
struct gpargs *args = (struct gpargs *)addr;
#else
struct gpargs args;
if (copyin(addr, (caddr_t)&args, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
status.lchdir = (cmd == NIOGET ? INPUT : OUTPUT);
status.lchnum = ARGS(lch);
ustatus = ARGS(status);
usaddr = ARGS(addr);
ulen = ARGS(len);
for(cp=sninfop->snlink[mdev]; cp; cp=cp->link) {
if( cp->lchnum == ARGS(lch)
&& cp->lmachno == ARGS(lmachno)) {
do_getput:
bp = (cmd == NIOGET ? &cp->input : &cp->output);
if( cmd == NIOPUT ) {
copyin(usaddr, bp->buf, ulen);
spl5();
bp->len = (ulen+1)/2;
snxstart(unit, cp, DATA);
sninfop->snsdata++;
} else {
spl5();
/*
* The following may be
* unnecessary in light of
* the later check.
*/
if( bp->done == 0 && cp->flags&SENTRNR ) {
cp->flags &= ~SENTRNR;
cp->flags |= SENTRDY;
snxstart(unit, cp, RDY);
sninfop->sns1rdy++;
}
}
for (;;) {
spl5();
if (bp->done) break;
sleep((caddr_t)bp->buf, SNPRI);
#ifdef TIMEOUT
spl6();
if (cp->flags & RETRY) {
cp->flags &= ~RETRY;
sninfop->sntimeout++;
snxstart(unit, cp, (cp->flags&SENTDATA) ? DATA : RDY);
}
#endif TIMEOUT
}
status.code = ST_OK;
status.len = 2*bp->len;
if( cmd == NIOGET ) {
spl0();
copyout(bp->buf, usaddr, 2*bp->len);
spl5();
bp->len = MAXMSGLEN;
/*
* Believe it or not, we must check
* this here. This is because
* we lowered the ipl to do the
* copyout(). During that time
* another message may have tried
* to sneak in.
*/
if( cp->flags&SENTRNR ) {
cp->flags &= ~SENTRNR;
snxstart(unit, cp, RDY);
sninfop->snsrdy++;
}
} else
bp->len = 0;
bp->done = 0;
spl0();
error = 0;
goto cpyout;
}
}
status.code = ST_IARGS;
error = EIO;
cpyout:
copyout((caddr_t)&status, (caddr_t)ustatus, sizeof(status));
RETURN ( error );
}
case NIOGETM:
{
struct pair pair;
struct chdat *lchns[MAXMUX+1];
register struct chdat **chp = lchns, **chpe = lchns;
#ifdef BSD42
struct gmargs *args = (struct gmargs *)addr;
#else
struct gmargs args;
if (copyin(addr, (caddr_t)&args, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
status.lchdir = INPUT;
ustatus = ARGS(status);
usaddr = ARGS(addr);
ulen = ARGS(len);
for(i=0; i<MAXMUX; i++) {
if (copyin((caddr_t)ARGS(pairp++), (caddr_t)&pair,
sizeof(struct pair))) {
RETURN ( EFAULT );
}
if( pair.lchno == -1 )
break;
if (pair.lchno < 0 || pair.lchno >= 512
|| pair.lmachno < 0 || pair.lmachno >= 512) {
RETURN ( EBADF );
}
for(cp=sninfop->snlink[mdev]; cp; cp=cp->link) {
if( cp->lchnum == pair.lchno
&& cp->lmachno == pair.lmachno ) {
*chpe++ = cp;
break;
}
}
if( cp >= &sn_chans[NUMLCH] ) {
RETURN ( EBADF );
}
}
spl5();
for(chp=lchns; chp<chpe; chp++) {
if( (*chp)->flags&MULTIPLEX ) {
spl0();
RETURN ( EBUSY );
}
}
for(chp=lchns; chp<chpe; chp++)
(*chp)->flags |= MULTIPLEX;
loop:
spl5();
for(chp=lchns; chp<chpe; chp++) {
if( (*chp)->input.done ) {
goto gotone;
}
}
sleep((caddr_t)&sn_multiplex, SNPRI);
goto loop;
gotone:
cp = *chp;
for(chp=lchns; chp<chpe; chp++)
(*chp)->flags &= ~MULTIPLEX;
spl0();
status.lchnum = cp->lchnum;
cmd = NIOGET;
goto do_getput;
}
case NIOABORT:
case NIORESET: {
struct device *draddr;
#ifndef USG5
struct uba_device *ui;
#endif
#ifdef BSD42
struct raargs *args = (struct raargs *)addr;
#else
struct raargs args;
if (copyin(addr, (caddr_t)&args, sizeof(args))) {
RETURN ( EFAULT );
}
#endif
#ifdef USG5
draddr = sn_addr[unit];
#else
ui = sndinfo[unit];
draddr = (struct device *)ui->ui_addr;
#endif
spl5();
i = ARGS(machno) << 8;
draddr->drcs = CMD_MODE;
draddr->drout = (cmd == NIOABORT ? ABORT(i) : RESET(i));
draddr->drcs = EOP_MODE;
draddr->drout = 0;
draddr->drcs = DATA_MODE;
spl0();
return(0);
}
case NIOREADSTATUS:
#ifdef BSD42
copyout((caddr_t)sninfop, *(caddr_t *)addr,
sizeof sn_sninfo[0]);
#else
copyout((caddr_t)sninfop, (caddr_t)addr,
sizeof sn_sninfo[0]);
#endif
return(0);
case NIOCHSTATUS: {
struct chinfo chinfo;
chinfo.numlch = NUMLCH;
chinfo.chanaddr = &sn_chans[0];
#ifdef BSD42
copyout((caddr_t)&chinfo, *(caddr_t *)addr,
sizeof chinfo);
copyout((caddr_t)chinfo.chanaddr,
(*(caddr_t *)addr)+sizeof chinfo,
NUMLCH*sizeof sn_chans[0]);
#else
copyout((caddr_t)&chinfo, (caddr_t)addr,
sizeof chinfo);
copyout((caddr_t)chinfo.chanaddr,
(caddr_t)(addr+sizeof chinfo),
NUMLCH*sizeof sn_chans[0]);
#endif
return(0);
}
case NIOSETMACH:
#ifdef BSD42
copyin(*(caddr_t *)addr, (caddr_t)snmach, sizeof snmach);
#else
copyin((caddr_t)addr, (caddr_t)snmach, sizeof snmach);
#endif
return(0);
case NIOGETMACH:
#ifdef BSD42
copyout((caddr_t)snmach, *(caddr_t *)addr, sizeof snmach);
#else
copyout((caddr_t)snmach, (caddr_t)addr, sizeof snmach);
#endif
return(0);
case NIOQSTATUS: {
struct openinfo openinfo;
openinfo.owaddr = sn_openwait;
openinfo.head = sn_owhead;
openinfo.tail = sn_owtail;
#ifdef BSD42
copyout((caddr_t)&openinfo, *(caddr_t *)addr, sizeof openinfo);
copyout((caddr_t)sn_openwait,
(*(caddr_t *)addr)+sizeof openinfo,
NUMDEV*sizeof sn_openwait[0]);
#else
copyout((caddr_t)&openinfo, (caddr_t)addr, sizeof openinfo);
copyout((caddr_t)sn_openwait, (caddr_t)(addr+sizeof openinfo),
NUMDEV*sizeof sn_openwait[0]);
#endif
return(0);
}
case NIOZEROSTAT:
{
register char *p, *low, *high;
low = (char *) &sn_sninfo[0];
#ifdef USG5
high = low + sn_cnt*sizeof (struct sninfo);
#else
high = low + NSN*sizeof (struct sninfo);
#endif
for (p=low; p<high; p++)
*p = '\0';
return(0);
}
case NIOCHECK:
case NIOWAIT:
case NIOPURGE:
case NIOSETVEC:
;
}
}
static
chclose(cp)
register struct chdat *cp;
{
cp->lchnum = cp->dlchnum = cp->machno = -1;
cp->flags = cp->xchan = cp->input.len = 0;
}
#ifdef TIMEOUT
cktimchk()
{
register struct chdat *cp;
register struct sninfo *sninfop;
int unit;
int s;
for(cp=sn_chans; cp < &sn_chans[NUMLCH]; cp++) {
if( cp->flags&(SENTDATA|SENTRDY) && --cp->ckticks == 0 ) {
unit = cp->snunit;
sninfop = &sn_sninfo[unit];
sninfop->snsched++;
sninfop->snenqlost[cp->machno]++;
cp->flags |= RETRY;
if (cp->flags & SENTDATA) {
wakeup((caddr_t)cp->output.buf);
} else {
wakeup((caddr_t)cp->input.buf);
}
}
}
s = spl6();
if (sn_state & OPEN) {
timeout(cktimchk, (caddr_t)0, CKTICKS);
} else {
sn_state &= ~TIMER;
}
splx(s);
}
#endif TIMEOUT
#endif