~kris/9p

9hist

f029e17b9e3835e385605837504e51e4f18b428a — David du Colombier 27 years ago c3b211c
Plan 9 from Bell Labs 1998-09-30
4 files changed, 183 insertions(+), 133 deletions(-)

M ip/il.c
M ip/ipifc.c
M pc/ether82557.c
M port/devsd.c
M ip/il.c => ip/il.c +86 -73
@@ 15,6 15,7 @@ enum				/* Connection state */
	Ilestablished,
	Illistening,
	Ilclosing,
	Ilopening,		/* only for file server */
};

char	*ilstates[] = 


@@ 24,7 25,8 @@ char	*ilstates[] =
	"Syncee",
	"Established",
	"Listening",
	"Closing" 
	"Closing",
	"Opening",		/* only for file server */
};

enum				/* Packet types */


@@ 49,7 51,26 @@ char	*iltype[] =
	"close" 
};

static char *etime = "connection timed out";
enum
{
	Seconds		= 1000,
	Iltickms 	= 50,		/* time base */
	AckDelay	= 2*Iltickms,	/* max time twixt message rcvd & ack sent */
	MaxTimeout 	= 4*Seconds,	/* max time between rexmit */
	QueryTime	= 5*Seconds,	/* time between subsequent queries */
	DeathTime	= 5*QueryTime,

	MaxRexmit 	= 16,		/* max retransmissions before hangup */
	Defaultwin	= 20,

	LogAGain	= 3,
	AGain		= 1<<LogAGain,
	LogDGain	= 2,
	DGain		= 1<<LogDGain,

	DefByteRate	= 100,		/* assume a megabit link */
	DefRtt		= 50,		/* cross country on a great day */
};

enum
{


@@ 64,7 85,7 @@ struct Ilcb			/* Control block */
	QLock	ackq;		/* Unacknowledged queue */
	Block	*unacked;
	Block	*unackedtail;
	ulong	unackeduchars;
	ulong	unackedbytes;
	QLock	outo;		/* Out of order packet queue */
	Block	*outoforder;
	ulong	next;		/* Id of next to send */


@@ 73,6 94,7 @@ struct Ilcb			/* Control block */
	ulong	start;		/* Local start id */
	ulong	rstart;		/* Remote start id */
	int	window;		/* Maximum receive window */
	int	rxquery;	/* number of queries on this connection */
	int	rxtot;		/* number of retransmits on this connection */
	int	rexmit;		/* number of retransmits of *unacked */
	ulong	qt[Nqt+1];	/* state table for query messages */


@@ 148,26 170,6 @@ struct Ilpriv
	QLock	apl;
};

enum
{
	Seconds		= 1000,
	Iltickms 	= 50,		/* time base */
	AckDelay	= 2*Iltickms,	/* max time twixt message rcvd & ack sent */
	MaxTimeout 	= 4*Seconds,	/* max time between rexmit */
	QueryTime	= 5*Seconds,	/* time between subsequent queries */
	DeathTime	= 5*QueryTime,

	MaxRexmit 	= 10,		/* max retransmissions before hangup */
	Defaultwin	= 20,

	LogAGain	= 3,
	AGain		= 1<<LogAGain,
	LogDGain	= 2,
	DGain		= 1<<LogDGain,
	DefByteRate	= 1000,		/* 10 meg ether */
	DefRtt		= 50,		/* cross country on a great day */
};

/* state for query/dataquery messages */




@@ 191,8 193,8 @@ void	ilcbinit(Ilcb*);

	int 	ilcksum = 1;
static 	int 	initseq = 25001;
static	int	microshift;

static	int	timeshift, timeround;
static	char	*etime = "connection timed out";

static char*
ilconnect(Conv *c, char **argv, int argc)


@@ 211,10 213,10 @@ ilstate(Conv *c, char *state, int n)
	Ilcb *ic;

	ic = (Ilcb*)(c->ptcl);
	return snprint(state, n, "%s del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d max %5.5d",
	return snprint(state, n, "%s del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d rxq %5.5d max %5.5d",
		ilstates[ic->state],
		ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain,
		ic->unackeduchars, ic->rxtot, ic->maxrtt);
		ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt);
}

static int


@@ 391,7 393,7 @@ ilackq(Ilcb *ic, Block *bp)
		ic->unacked = np;
	ic->unackedtail = np;
	np->list = nil;
	ic->unackeduchars += n;
	ic->unackedbytes += n;
}

static


@@ 399,47 401,48 @@ void
ilrttcalc(Ilcb *ic, Block *bp)
{
	uvlong fastrtt;
	int rtt, tt, pt, delay, rate, mrtt;
	int rtt, tt, pt, delay, rate;

	fastrtt = fastticks(nil) - ic->rttstart;
	if(microshift >= 0)
		rtt = fastrtt >> microshift;
	else
		rtt = fastrtt << -microshift;
	mrtt = rtt >> 10;
	if(timeshift >= 0)
		rtt = fastrtt >> timeshift;
	else {
		rtt = fastrtt;
		rtt = (rtt<<-timeshift)+timeround;
	}
	delay = ic->delay;
	rate = ic->rate;

	/* Guard against zero wrap */
	if(rtt > 120000000)
	if(rtt > 120000)
		return;

	/* guess fixed delay as rtt of small packets */
	if(ic->rttlen < 128){
		delay += mrtt - (delay>>LogAGain);
		if(delay < AGain)
			delay = AGain;
		ic->delay = delay;
	}

	/* this block had to be transmitted after the one acked so count its size */
	ic->rttlen += blocklen(bp)  + IL_IPSIZE + IL_HDRSIZE;

	/* if packet took longer than round trip delay, reset rate */
	tt = mrtt - (delay>>LogAGain);
	if(tt > 0){
		rate += ic->rttlen/tt - (rate>>LogAGain);
		if(rate < AGain)
			rate = AGain;
		ic->rate = rate;
	if(ic->rttlen < 256){
		/* guess fixed delay as rtt of small packets */
		delay += rtt - (delay>>LogAGain);
		if(delay < AGain)
			delay = AGain;
		ic->delay = delay;
	} else {
		/* if packet took longer than avg rtt delay, recalc rate */
		tt = rtt - (delay>>LogAGain);
		if(tt > 0){
			rate += ic->rttlen/tt - (rate>>LogAGain);
			if(rate < AGain)
				rate = AGain;
			ic->rate = rate;
		}
	}

	/* mdev */
	pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain);
	ic->mdev += abs(mrtt-pt) - (ic->mdev>>LogDGain);
	ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain);

	if(mrtt > ic->maxrtt)
		ic->maxrtt = mrtt;
	if(rtt > ic->maxrtt)
		ic->maxrtt = rtt;
}

void


@@ 465,7 468,7 @@ ilackto(Ilcb *ic, ulong ackto, Block *bp)
		bp = ic->unacked;
		ic->unacked = bp->list;
		bp->list = nil;
		ic->unackeduchars -= blocklen(bp);
		ic->unackedbytes -= blocklen(bp);
		freeblist(bp);
		ic->rexmit = 0;
		ilsettimeout(ic);


@@ 683,6 686,8 @@ _ilprocess(Conv *s, Ilhdr *h, Block *bp)
			freeblist(bp);
			break;
		case Ilstate:
			if(ack >= ic->rttack)
				ic->rttack = 0;
			ilackto(ic, ack, bp);
			if(h->ilspec > Nqt)
				h->ilspec = 0;


@@ 728,6 733,7 @@ ilrexmit(Ilcb *ic)
	Block *nb;
	Conv *c;
	ulong id;
	Ilpriv *priv;

	nb = nil;
	qlock(&ic->ackq);


@@ 753,12 759,14 @@ ilrexmit(Ilcb *ic)
		ic->rexmit, ic->timeout,
		c->raddr, c->lport, c->rport);

	/* rtt calcs are useless during retransmissions */
	ic->rttack = 0;

	ilbackoff(ic);

	ipoput(c->p->f, nb, 0, ic->conv->ttl);

	/* statistics */
	ic->rxtot++;
	priv = c->p->priv;
	priv->rexmit++;
}

/* DEBUG */


@@ 962,8 970,10 @@ ilsettimeout(Ilcb *ic)
{
	ulong pt;

	pt = (ic->delay>>LogAGain) + ic->unackeduchars/(ic->rate>>LogAGain) + ic->mdev;
	pt += AckDelay;
	pt = (ic->delay>>LogAGain)
		+ ic->unackedbytes/(ic->rate>>LogAGain)
		+ (ic->mdev>>(LogDGain-1))
		+ AckDelay;
	if(pt > MaxTimeout)
		pt = MaxTimeout;
	ic->timeout = msec + pt;


@@ 974,21 984,18 @@ ilbackoff(Ilcb *ic)
{
	ulong pt;
	int i;
	Ilpriv *priv;

	pt = (ic->delay>>LogAGain) + ic->unackeduchars/(ic->rate>>LogAGain) + ic->mdev;
	pt += AckDelay;
	pt = (ic->delay>>LogAGain)
		+ ic->unackedbytes/(ic->rate>>LogAGain)
		+ (ic->mdev>>(LogDGain-1))
		+ AckDelay;
	for(i = 0; i < ic->rexmit; i++)
		pt = pt + (pt>>1);
	if(pt > MaxTimeout)
		pt = MaxTimeout;
	ic->timeout = msec + pt;

	ic->rxtot++;
	ic->rexmit++;

	priv = ic->conv->p->priv;
	priv->rexmit++;
}

void


@@ 1053,7 1060,9 @@ loop:
					ilhangup(p, etime);
					break;
				}
				ilrexmit(ic);
				ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
				ic->rxquery++;
				ilbackoff(ic);
			}
			break;
		}


@@ 1068,7 1077,7 @@ ilcbinit(Ilcb *ic)
	ic->next = ic->start+1;
	ic->recvd = 0;
	ic->window = Defaultwin;
	ic->unackeduchars = 0;
	ic->unackedbytes = 0;
	ic->unacked = nil;
	ic->outoforder = nil;
	ic->rexmit = 0;


@@ 1200,21 1209,25 @@ ilnextqt(Ilcb *ic)
	return x;
}

/* quick and dirty conversion from fastticks to microseconds */
/* calculate shift that converts fast ticks to ms (more or less) */
static void
initfast(void)
inittimeshift(void)
{
	int i;
	uvlong x, hz;

	fastticks(&hz);
	x = 3;
	for(i = 1; i < 40; i++){
	for(i = 1; i < 45; i++){
		if(x >= hz)
			break;
		x <<= 1;
	}
	microshift = i - 20;
	timeshift = i - 10;
	if(i < 0)
		timeround = (1<<-i)-1;
	else
		timeround = 0;
}

void


@@ 1222,7 1235,7 @@ ilinit(Fs *f)
{
	Proto *il;

	initfast();
	inittimeshift();

	il = smalloc(sizeof(Proto));
	il->priv = smalloc(sizeof(Ilpriv));

M ip/ipifc.c => ip/ipifc.c +0 -1
@@ 483,7 483,6 @@ ipifcrem(Ipifc *ifc, char **argv, int argc, int dolock)

	free(lifc);

out:
	if(dolock)
		wunlock(ifc);
	return nil;

M pc/ether82557.c => pc/ether82557.c +82 -58
@@ 570,11 570,90 @@ transmit(Ether* ether)
}

static void
interrupt(Ureg*, void* arg)
receive(Ether* ether)
{
	Rfd *rfd;
	Ctlr *ctlr;
	int count;
	Block *bp, *pbp, *xbp;

	ctlr = ether->ctlr;
	bp = ctlr->rfdhead;
	for(rfd = (Rfd*)bp->rp; rfd->field & RfdC; rfd = (Rfd*)bp->rp){
		/*
		 * If it's an OK receive frame
		 * 1) save the count 
		 * 2) if it's small, try to allocate a block and copy
		 *    the data, then adjust the necessary fields for reuse;
		 * 3) if it's big, try to allocate a new Rfd and if
		 *    successful
		 *	adjust the received buffer pointers for the
		 *	  actual data received;
		 *	initialise the replacement buffer to point to
		 *	  the next in the ring;
		 *	initialise bp to point to the replacement;
		 * 4) if there's a good packet, pass it on for disposal.
		 */
		if(rfd->field & RfdOK){
			pbp = nil;
			count = rfd->count & 0x3FFF;
			if((count < ETHERMAXTU/4) && (pbp = iallocb(count))){
				memmove(pbp->rp, bp->rp+sizeof(Rfd)-sizeof(rfd->data), count);
				pbp->wp = pbp->rp + count;

				rfd->count = 0;
				rfd->field = 0;
			}
			else if(xbp = rfdalloc(rfd->link)){
				bp->rp += sizeof(Rfd)-sizeof(rfd->data);
				bp->wp = bp->rp + count;

				xbp->next = bp->next;
				bp->next = 0;

				pbp = bp;
				bp = xbp;
			}
			if(pbp != nil)
				etheriq(ether, pbp, 1);
		}
		else{
			rfd->count = 0;
			rfd->field = 0;
		}

		/*
		 * The ring tail pointer follows the head with with one
		 * unused buffer in between to defeat hardware prefetch;
		 * once the tail pointer has been bumped on to the next
		 * and the new tail has the Suspend bit set, it can be
		 * removed from the old tail buffer.
		 * As a replacement for the current head buffer may have
		 * been allocated above, ensure that the new tail points
		 * to it (next and link).
		 */
		rfd = (Rfd*)ctlr->rfdtail->rp;
		ctlr->rfdtail = ctlr->rfdtail->next;
		ctlr->rfdtail->next = bp;
		((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp);
		((Rfd*)ctlr->rfdtail->rp)->field |= RfdS;
		coherence();
		rfd->field &= ~RfdS;

		/*
		 * Finally done with the current (possibly replaced)
		 * head, move on to the next and maintain the sentinel
		 * between tail and head.
		 */
		ctlr->rfdhead = bp->next;
		bp = ctlr->rfdhead;
	}
}

static void
interrupt(Ureg*, void* arg)
{
	Cb* cb;
	Block *bp, *xbp;
	Ctlr *ctlr;
	Ether *ether;
	int status;


@@ 599,62 678,7 @@ interrupt(Ureg*, void* arg)
			ctlr->tick = 0;

		if(status & StatFR){
			bp = ctlr->rfdhead;
			rfd = (Rfd*)bp->rp;
			while(rfd->field & RfdC){
				/*
				 * If it's an OK receive frame and a replacement buffer
				 * can be allocated then
				 *	adjust the received buffer pointers for the
				 *	  actual data received;
				 *	initialise the replacement buffer to point to
				 *	  the next in the ring;
				 *	pass the received buffer on for disposal;
				 *	initialise bp to point to the replacement.
				 * If not, just adjust the necessary fields for reuse.
				 */
				if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){
					bp->rp += sizeof(Rfd)-sizeof(rfd->data);
					bp->wp = bp->rp + (rfd->count & 0x3FFF);

					xbp->next = bp->next;
					bp->next = 0;

					etheriq(ether, bp, 1);
					bp = xbp;
				}
				else{
					rfd->field = 0;
					rfd->count = 0;
				}

				/*
				 * The ring tail pointer follows the head with with one
				 * unused buffer in between to defeat hardware prefetch;
				 * once the tail pointer has been bumped on to the next
				 * and the new tail has the Suspend bit set, it can be
				 * removed from the old tail buffer.
				 * As a replacement for the current head buffer may have
				 * been allocated above, ensure that the new tail points
				 * to it (next and link).
				 */
				rfd = (Rfd*)ctlr->rfdtail->rp;
				ctlr->rfdtail = ctlr->rfdtail->next;
				ctlr->rfdtail->next = bp;
				((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp);
				((Rfd*)ctlr->rfdtail->rp)->field |= RfdS;
				coherence();
				rfd->field &= ~RfdS;

				/*
				 * Finally done with the current (possibly replaced)
				 * head, move on to the next and maintain the sentinel
				 * between tail and head.
				 */
				ctlr->rfdhead = bp->next;
				bp = ctlr->rfdhead;
				rfd = (Rfd*)bp->rp;
			}
			receive(ether);
			status &= ~StatFR;
		}


M port/devsd.c => port/devsd.c +15 -1
@@ 122,6 122,7 @@ sdinit(void)
			 */
			nbytes = 0xFF;
			memset(scratch, 0, nbytes);

			if(scsiinquiry(d->t, d->lun, scratch, &nbytes) != STok)
				continue;
			if(scratch[0] == 0x7F)


@@ 140,8 141,21 @@ sdinit(void)
				nbytes = 0xFF;
				memset(scratch, 0, nbytes);
				scsireqsense(d->t, 0, scratch, &nbytes, 1);
				if((scratch[2] & 0x0F) != 0x02 && (scratch[2] & 0x0F) != 0)
				switch(scratch[2] & 0x0F){

				case 0x00:
				case 0x01:
				case 0x02:
					break;
				case 0x06:
					if(scratch[12] == 0x28 && scratch[13] == 0)
						break;
					if(scratch[12] == 0x29 && scratch[13] == 0)
						break;
					/*FALLTHROUGH*/
				default:
					continue;
				}
				if(type == TypeDA)
					scsistart(d->t, d->lun, 0);
				d->size = d->bsize = 0;