File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / bsc / bscpsm.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
Power 6/32 Unix version 1.2b

#include "../bsc/local.h"
#include "../bsc/bscio.h"
#include "../bsc/bsc.h"

/*	D.L.Buck and Associates, Inc. - %H%
 *
 *	COPYRIGHT NOTICE:
 *		Copyright c %H% - An unpublished work by 
 *		D.L.Buck and Associates, Inc.
 *
 *	PROPRIETARY RIGHTS NOTICE:
 *		All rights reserved. This document and program contains
 *		proprietary information of D.L.Buck and Associates,Inc.
 *		of San Jose, California, U.S.A., embodying confidential
 *		information,  ideas, and expressions,  no part of which
 *		may be reproduced, or transmitted in any form or by any
 *		means,  electronic,  mechanical,  or otherwise, without
 *		the written permission of D.L.Buck and Associates, Inc.
 *
 * NAME
 *	bscpsm -- BISYNC Single- or Multi-station Protocol State Machine
 *
 * DESCRIPTION
 *	The BISYNC protocol is implemented via a state machine. The state
 *	machine consists of a state table, the state machine algorithm,
 *	and a set of state actions.
 *
 *	Each state in the state machine is either a 'send', 'receive',
 *	'decision', 'function', or 'error' state. Each has a particular
 *	action associated with it. Before defining the state table for the
 *	protocol state machine, we introduce the state enumerations for use
 *	in subsequent definitions.
 */

#ifndef lint
static char bscpm_c[] = "%W% %Q%";
#endif

long TWAIT = 2;

#define	START	0		/* starting state */
#define	PTPT	1		/* Starting state for point-to-point */
#define	SNDBID	2		/* pt-pt write; send bid */
#define	WTBIDA	3		/* wait bid acknowledgement */
#define	CKHOST	4		/* check host id */
#define	CKXMIT	5		/* check transmit buffer */
#define	SNDTXT	6		/* send text block */
#define	WTTXTA	7		/* wait text acknowledgement */
#define	RGTACK	8		/* check for correct ack */
#define	XFLIP	9		/* flip even/odd block indicator */
#define	SNDTTD	10		/* text buffer empty - send ttd */
#define	WTTTDA	11		/* wait for ttd acknowledgement */
#define	PROERR	12		/* error - protocol violation */
#define	SNDEOT	13		/* send eot */
#define	RTYERR	14		/* error - # retries exceeded */
#define	WNGACK	15		/* wrong acknowledgement */
#define	CKNWAK	16		/* check wack counter */
#define	WAKERR	17		/* error - too many wack's */
#define	CKNRTY	18		/* check # retries */
#define	CHKRVI	19		/* check action on rvi */
#define	RVIERR	20		/* error - rvi received */
#define	RTOENQ	21		/* send enq for timeout */
#define	WTRTOA	22		/* wait for response to timeout enq */
#define	CKNRT2	23		/* check # retries */
#define	CORACK	24		/* check for correct acknowledgement */
#define	BIDEOT	25		/* send eot then rebid */
#define	CKNBID	26		/* check # bids sent */
#define	BIDERR	27		/* error - bid count exceeded */
#define	HSTERR	28		/* error - wrong host id */
#define	DONE	29		/* transmit complete */
#define	WTPTPT	30		/* wait for point-to-point enq */
#define	SETODD	31		/* set odd block count */
#define	CKRDY	32		/* check rcv buffer availability */
#undef DELAY
#define	DELAY	33		/* send wack */
#define	WTWAKA	34		/* wait wack acknowledgement */
#define	SNDLST	35		/* send last acknowledgement */
#define	WTTEXT	36		/* receive text */
#define	CKBCC	37		/* check bcc */
#define	NAKERR	38		/* error - too many nak's */
#define	SNDNAK	39		/* send nak */
#define	CKNTTD	40		/* check # ttd's */
#define	TTDERR	41		/* error - too many ttd's */
#define	CKABTM	42		/* check for abnormal termination */
#define	RXEEOF	43		/* error - early eof */
#define	RDONE	44		/* receive complete */
#define	SNDDSC	45		/* line closed - send disconnect */
#define	XTO	46		/* error - transmit timeout */
#define	NODSR	47		/* error - modem dropped DSR */
#define	CONTND	48		/* error - line contention on send */
#define	MPT	49		/* multipoint poll receive */
#define	CKMPT	50		/* check multipoint address */
#define	MPTCNT	51		/* mulipoint contention */
#define	FASTAK	52		/* fast acknowledge */
#define	POLEOT	53		/* send eot to poll */
#define	TOOBIG	54		/* Received block was greater than BSCMBLK */
#define	SETLST	55		/* Set "last sent" to ack0/1		*/
extern long nvbsc;
extern struct bsc bsc[];
#ifdef NBSM
extern struct bscsub bscsubs[NBSM][NBSSUB];
extern char ascdev[],ebcdev[];
#endif

/*
 *	There are NX different transmission messages, as follows:
 */
#define	X_BID	0	/* initial bid request */
#define	X_TXT	1	/* text message */
#define	X_TTD	2	/* temporary transmit delay */
#define	X_EOT	3	/* end of transmission */
#define	X_ENQ	4	/* repeat last message request */
#define	X_LST	5	/* send last acknowledgement */
#define	X_WAK	6	/* acknowledge with wait request */
#define	X_NAK	7	/* negative acknowledgement */
#define	X_DSC	8	/* disconnect */
#define	X_BAK	9	/* bid acknowledgement */
#define	NX	10	/* number of transmission messages */

/* These are the ASCII messages and message components: */

typedef struct xlist xl;
					/* initial bid */
xl ascbid[] = { { 0, 0 }, { 1, "\005" }, {0,0} };
					/* init bid response */
xl ascbak[] = { { 0, 0 }, { 2, "\020\060" }, {0,0} };
					/* text block */
xl asctxt[] = { { 1, "" },	/* stx or soh */
		{ 0, "" },	/* data */
		{ 0, "\020" },	/* if transparent, len = 1 */
		{ 0, "" },	/* etb or etx */
#ifdef MANCRC
		{ 1, "" },	/* crc */
#endif
		{0,0} };	/* changed! */
        xl astx = { 1, "\002" };	/* start of text block */
        xl atstx = { 2, "\020\002" };	/* start of transparent text block */
        xl asoh = { 1, "\001" };	/* start of header */
        xl atsoh = { 2, "\020\001" };	/* start of transparent header */
        xl aetb = { X_CRC|1, "\027" };	/* end intermediate text blk */
        xl aetx = { X_CRC|1, "\003" };	/* end last text block */
xl ascttd[] = { { 2, "\002\005" }, {0,0} };	/* temp. xmit delay */
xl asceot[] = { { 1, "\004" }, {0,0} };		/* end of transmission */
xl ascenq[] = { { 1, "\005" }, {0,0} };		/* enquiry */
xl asclst[] = { { 2, "" }, {0,0} };	/* changed! */
        xl aack0 = {2, "\020\060" };	/* even acknowledgement */
        xl aack1 = {2, "\020\061" };	/* odd  acknowledgement */
xl ascwak[] = { { 2, "\020\073" }, {0,0} };	/* acknowledge with wait */
xl ascnak[] = { { 1, "\025" }, {0,0} }; /* negative acknowledgement */
xl ascdsc[] = { { 2, "\020\004" }, {0,0} };	/* disconnect sequence */
xl *asclist[] = {ascbid, asctxt, ascttd, asceot, ascenq, asclst, ascwak,
		 ascnak, ascdsc, ascbak};

/* ebcdic transmit lists */
					/* initial bid */
xl ebcbid[] = { { 0, 0 }, { 1, "\055" }, {0,0} };
					/* init bid response */
xl ebcbak[] = { { 0, 0 }, { 2, "\020\160" }, {0,0} };
					/* text block */
xl ebctxt[] = { { 1, "" },	/* stx or soh */
		{ 0, "" },	/* data */
		{ 0, "\020" },	/* if transparent, len = 1 */
		{ 0, "" },	/* etb or etx */
#ifdef MANCRC
		{ 2, "" },	/* crc */
#endif
		{0,0} };	/* changed! */
        xl estx = { 1, "\002" };	/* start of text block */
        xl etstx = { 2, "\020\002" };	/* start of transparent text block */
        xl esoh = { 1, "\001" };	/* start of header */
        xl etsoh = { 2, "\020\001" };	/* start of transparent header */
        xl eetb = { X_CRC|1, "\046" };	/* end intermediate text blk */
        xl eetx = { X_CRC|1, "\003" };	/* end last text block */
xl ebcttd[] = { { 2, "\002\055" }, {0,0} };	/* temp. xmit delay */
xl ebceot[] = { { 1, "\067" }, {0,0} };	/* end of transmission */
xl ebcenq[] = { { 1, "\055" }, {0,0} };	/* enquiry */
xl ebclst[] = { { 2, "" }, {0,0} };	/* changed! */
        xl eack0 = {2, "\020\160" };	/* even acknowledgement */
        xl eack1 = {2, "\020\141" };	/* odd  acknowledgement */
xl ebcwak[] = { { 2, "\020\153" }, {0,0} };	/* acknowledge with wait */
xl ebcnak[] = { { 1, "\075" }, {0,0} }; /* negative acknowledgement */
xl ebcdsc[] = { { 2, "\020\067" }, {0,0} };	/* disconnect sequence */
xl *ebclist[] = {ebcbid, ebctxt, ebcttd, ebceot, ebcenq, ebclst, ebcwak,
		 ebcnak, ebcdsc, ebcbak};

/* receive lists - both transmission codes
 *
 * Each receive list is a string of the different states to which to
 * transfer based on the level-0 packet classification.
 * This string indexed by a frame type (see bsc.h) gives the state for the
 * corresponding packet class.
 */

char rlbida[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	CKNBID,CKNBID,BIDEOT,BIDEOT,BIDEOT,CKNBID,BIDEOT,CKHOST,BIDEOT,BIDEOT};
char rltxta[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	PROERR,PROERR,CKNRTY,FASTAK,FASTAK,CKNWAK,CHKRVI,RGTACK,RGTACK,PROERR};
char rlttda[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	PROERR,PROERR,CKXMIT,PROERR,PROERR,PROERR,PROERR,PROERR,PROERR,PROERR};
char rlrtoa[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	CKNRT2,PROERR,CKNRTY,FASTAK,FASTAK,CKNWAK,CHKRVI,CORACK,CORACK,CKNRT2};
char rlptpt[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	SETODD,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT,WTPTPT};
char rltext[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	SETLST,CKABTM,WTTEXT,CKBCC, CKBCC, WTTEXT,WTTEXT,WTTEXT,WTTEXT,CKNTTD};
char rlwaka[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	CKRDY,RXEEOF,WTWAKA,PROERR,PROERR,WTWAKA,WTWAKA,WTWAKA,WTWAKA,PROERR};
char rlwtps[NC] = {
/*	- enq  - eot  - nak  - etx  - etb  - wak  - rvi  - ak0	- ak1  - ttd */
	CKMPT, CKMPT, MPT,   MPT,   MPT,   MPT,   MPT,   MPT,   MPT,   MPT   };

/*
 *	There are NR different receive lists, as shown above; these
 *	are numbered for use in the protocol state entry for a receive
 *	operation. The following constants index 'rlist' to provide a pointer
 *	to the appropriate receive list.
 */
#define	R_BIDA	0	/* bid acknowledgement wait */
#define	R_TXTA	1	/* text acknowledgement wait */
#define	R_TTDA	2	/* temp. text delay ack. wait */
#define	R_RTOA	3	/* response time out wait */
#define	R_PTPT	4	/* point-to-point bid wait */
#define	R_TEXT	5	/* wait for text */
#define	R_WAKA	6	/* wait for response to wack message */
#define	R_POLSEL 7	/* wait for poll/select */
#define	NR	8	/* number of receive lists */

char *rlist[NR] = {rlbida, rltxta, rlttda, rlrtoa, rlptpt, rltext, rlwaka,
		   rlwtps};

/*
 * PSM states may consist of decision functions, which decide for themselves
 * what the following state will be, and ordinary functions, which have the
 * next state decided for them in the PSM state table.
 * Each function is represented by an ordinal in the state table, as follows:
 */
#define	D_START 	0	/* decide multipoint vs point-to-point */
#define	D_PTPT		1	/* decide on send vs receive */
#define	D_CKHOST	2	/* check correctness of host id */
#define	D_CKXMIT	3	/* check status of xmit buffer */
#define	D_RGTACK	4	/* check to see if ack is right */
#define	D_XFLIP 	5	/* flip even/odd indicator - block recv'd */
#define	D_CKNWAK	6	/* check max wacks allowed */
#define	D_CKNRTY	7	/* check max retries allowed */
#define	D_CHKRVI	8	/* check rvi action */
#define	D_CKNRT2	9	/* check max retries allowed */
#define	D_CORACK	10	/* check current vs previous ack */
#define	D_CKNBID	11	/* check max bids allowed */
#define	F_SETODD	12	/* set odd block expected */
#define	D_CKRDY 	13	/* check status of rcv buffer */
#define	D_CKBCC 	14	/* check last block's crc */
#define	D_CKNTTD	15	/* check max ttd's allowed */
#define	D_CKABTM	16	/* check for normal transmission termination */
#define	D_CKMPT		17	/* check poll/select address */
#define	D_FASTACK	18	/* wait during fast acknowledge */
#define	F_SETLST	19	/* Set even/odd ackn. message		*/

struct state states[] = {
	{ 'd', 0, D_START },	/*  0 decide on pt-pt vs multipoint */
	{ 'd', 0, D_PTPT },	/*  1 decide on send vs receive */
	{ 's', WTBIDA, X_BID }, /*  2 send ENQ (bid) */
	{ 'r', CKNBID, R_BIDA },/*  3 receive bid acknowledgement */
	{ 'd', 0, D_CKHOST },	/*  4 check to see if right host id */
	{ 'd', 0, D_CKXMIT },	/*  5 check for full transmit buffer */
	{ 's', WTTXTA, X_TXT }, /*  6 send stx, data, et[bx], ... */
	{ 'r', RTOENQ, R_TXTA}, /*  7 wait text acknowledgement */
	{ 'd', 0, D_RGTACK },	/*  8 check for correct acknowledgement */
	{ 'f', CKXMIT, D_XFLIP},/*  9 flip even/odd indicator */
	{ 's', WTTTDA, X_TTD }, /* 10 send temp. text delay */
	{ 'r', CKXMIT, R_TTDA },/* 11 wait proper response (nak) */
	{ 'e', SNDEOT,BSCPROTO},/* 12 protocol error - funny response */
	{ 's', START, X_EOT },	/* 13 send eot */
	{ 'e', SNDEOT,BSCNRETR},/* 14 NRETRY limit exceeded */
	{ 's', WTTXTA, X_ENQ},	/* 15 wrong ack - send enq */
	{ 'd', 0, D_CKNWAK },	/* 16 check # wacks received in a row */
	{ 'e', SNDEOT,BSCNWACK},/* 17 NWACK limit exceeded */
	{ 'd', 0, D_CKNRTY },	/* 18 check # retries */
	{ 'd', 0, D_CHKRVI },	/* 19 check whether we abort or accept RVI */
	{ 'e', SNDEOT, BSCRVI },/* 20 error - RVI received */
	{ 's', WTRTOA, X_ENQ }, /* 21 receive timeout - send ENQ */
	{ 'r', CKNRT2, R_RTOA },/* 22 wait on acknowledgement to ENQ */
	{ 'd', 0, D_CKNRT2 },	/* 23 check # retries */
	{ 'd', 0, D_CORACK },	/* 24 check to see if we resend text */
	{ 's', CKNBID, X_EOT }, /* 25 bad response to bid */
	{ 'd', 0, D_CKNBID },	/* 26 check # bids */
	{ 'e', SNDEOT, BSCNBID},/* 27 error - too many unanswered bids */
	{ 'e', SNDEOT, BSCWHI}, /* 28 error - wrong host */
	{ 'e', SNDEOT, 0 },	/* 29 done! */
	{ 'r', WTPTPT, R_PTPT },/* 30 wait for line bid from other end */
	{ 'f', CKRDY, F_SETODD},/* 31 set odd response indicator */
	{ 'd', 0, D_CKRDY },	/* 32 check receive buffer available */
	{ 's', WTWAKA, X_WAK }, /* 33 buffer unavailable - send wack */
	{ 'r', WTWAKA, R_WAKA}, /* 34 wait wack acknowledgement */
	{ 's', WTTEXT, X_LST }, /* 35 send 'last response' */
	{ 'r', WTTEXT, R_TEXT}, /* 36 wait for text */
	{ 'd', 0, D_CKBCC },	/* 37 check bcc (crc or lrc) */
	{ 'e', SNDEOT, BSCNNAK},/* 38 error - nak limit exceeded */
	{ 's', WTTEXT, X_NAK }, /* 39 send nak (to TTD or bad text block) */
	{ 'd', 0, D_CKNTTD },	/* 40 check TTD limits */
	{ 'e', SNDEOT, BSCNTTD},/* 41 error - TTD limit exceeded */
	{ 'd', 0, D_CKABTM },	/* 42 check for normal eof or early eof */
	{ 'e', 0, BSCEEOF },	/* 43 early end of file */
	{ 'e', 0, 0 },		/* 44 normal end of receive */
	{ 's', START, X_DSC},	/* 45 send disconnect message */
	{ 'e', 0, BSCTXTO },	/* 46 error - xmit timeout */
	{ 'e', 0, BSCNDSR },	/* 47 error - no DSR */
	{ 'e', SNDEOT,BSCONTND},/* 48 error - line contention */
	{ 'r', MPT, R_POLSEL },	/* 49 MPT    Wait Poll/Select */
	{ 'd', 0, D_CKMPT },	/* 50 CKMPT  Check Poll/select address */
	{ 'e', MPT, BSCONTND },	/* 51 MPTCNT Multipoint contention */
	{ 'd', CKBCC,D_FASTACK},/* 52 FASTAK Wait during fast acknowledge */
	{ 's', MPT, X_EOT },	/* 53 POLEOT Respond negatively to poll */
	{ 'e', SNDEOT, BSC2BIG},/* 54 TOOBIG Rcvd block was too big	*/
	{ 'f', SNDLST,F_SETLST},/* 55 SETLST Set even/odd last send pointer */
};


bscpsm(dev)	/* protocol state machine */
register dev_t dev;
{
	register struct bsc *bp;
#ifdef NBSM
	register struct bscsub *bsp;
#endif
	register struct state *st;
	int x,xx;
	register int iflag, dflag;

	if (dev >= MX_NBSC)
		panic("bsc: unknown device#");
	bp = &bsc[dev];

	x = spl8();			/* Lock the door */
	if (bp->b_sema & BSC_INPSM) {	/* Someone have it locked? */
		splx(x);		/* Yes - leave quietly */
		return;
	}
	bp->b_sema |= BSC_INPSM;	/* Make sure no one else enters */
	splx(x);

	if (bp->b_mode == BSC_CL1) {	/* Need to send disconnect */
		bp->b_state = SNDDSC;	/* New state: send disconnect */
		bp->b_mode = BSC_CL2;	/* New mode: wait for disc complete */
	}

#ifdef NBSM
	if (bp->b_lock != SSLOCK)
		if (bp->b_psmbsy == -1)
			bsp = NULL;
		else
			bsp = &bscsubs[dev][bp->b_psmbsy];
#endif

	/* Main loop of Protocol State Machine */
	while (1) {
		st = &states[bp->b_state];

		/* If tracing engaged, trace this state */
		if (bp->b_trace)
			bsctr (dev, bp->b_state, st->s_type);
		switch (st->s_type) {
		case 'f':	/* function */
			bp->b_state = st->s_next;/* always use table's new st*/
		case 'd':	/* decision */
			iflag = bp->b_hlflgs;	/* temp copy of flag */
#ifdef NBSM
			dflag = (bp->b_lock == SSLOCK) ? iflag :
				(bsp?bsp->bs_flags:0);
			/* temp copy of device flags */
#else
			dflag = iflag;		/* same as iflag */
#endif
			switch (st->s_ord) {	/* do function */
			case D_START:
				if (bp->b_mode == BSC_CL2)
					bp->b_mode = BSC_CLOSED;
				if (bp->b_mode == BSC_CLOSED)
					goto closedoor;

#ifdef NBSM
				if (bp->b_lock == SSLOCK)
					x = bp->b_sema;
				else	x = (bsp)?bsp->bs_sema:BSC_DDONE;
#else
				x = bp->b_sema;
#endif
				if (x & BSC_DBUSY) {
					x = spl8();
					bp->b_alarm = PSMTPS;
					bp->b_alenb = 1;
					splx(x);
					goto closedoor;
				}
				bp->b_tmperr = 0;	/* zero tmperrs */
				if (iflag & BSCMPT) {	/* if multipoint, */
					bp->b_hlflgs |= BSC_POLLWT;
					bp->b_state = MPT;
				} else
					bp->b_state = PTPT;
				x = spl8();
				bp->b_sema |= BSC_PDONE;
				bp->b_sema &= ~BSC_PBUSY;
#ifdef NBSM
				if (bp->b_lock != SSLOCK && bsp) {
					bsp->bs_sema |= BSC_PDONE;
					bsp->bs_sema &= ~BSC_PBUSY;
					bsp = NULL;
					bp->b_psmbsy = -1;
				}
#endif
				splx(x);
				break;

			case D_PTPT:
				/* If we are to write, SNDBID; read, WTPTPT;
				 * otherwise, delay.
				 */
				/* If ready to write, check initial bid */
				for (x=0; x<sizeof bp->b_iocin.b_termid &&
					  bp->b_iocin.b_termid[x];
					  ++x);
				if (bp->b_mode == BSC_WRITE) {
					bp->b_state = SNDBID;
					bp->b_sema &= ~BSC_PDONE;
					bp->b_sema |= BSC_PBUSY;
					ascbid[0].xnum = x;
					ebcbid[0].xnum = x;
					ascbid[0].xptr = bp->b_iocin.b_termid;
					ebcbid[0].xptr = bp->b_iocin.b_termid;
					break;
				}
				if (bp->b_mode == BSC_READ) {
					bp->b_state = WTPTPT;
					bp->b_sema &= ~BSC_PDONE;
					bp->b_sema |= BSC_PBUSY;
					ascbak[0].xnum = x;
					ebcbak[0].xnum = x;
					ascbak[0].xptr = bp->b_iocin.b_termid;
					ebcbak[0].xptr = bp->b_iocin.b_termid;
					break;
				}
				/* else */
				wakeup ((caddr_t)bp->b_buffer);
				x = spl8();
				bp->b_alarm = PSMTPS;	/* wait 1 sec*/
				bp->b_alenb = 1;
				splx(x);
				goto closedoor;

			case D_CKHOST:
				/* 1. Set expected response to odd ackn.
				 *    Null our term id field - send once only.
				 * 2. If we are supposed to check host id,
				 *    compare received vs. given.
				 *    If different, HSTERR.
				 *    Normally, CKXMIT.
				 */
				bp->b_hlflgs |= BSC_ACK;	/* set odd */
				bp->b_iocin.b_termid[0] = '\0';
				bp->b_state = ((!(iflag & BSCCKHOST))
					|| bp->b_iocin.b_hostid[0] == '\0'
					|| bsccmp(bp->b_iocin.b_hostid,
						  bp->b_iocout.b_hostid)==0) ?
					CKXMIT : HSTERR;
				break;

			case D_CKXMIT:
				/* Check transmit buffer. If empty,
				 * wait up to 2 seconds; if still
				 * empty, send TTD.
				 */
				if (!(dflag & BSC_FULL)) { /* buffer empty */
					if (bp->b_alarm <= -100 &&
					    ++bp->b_bscto >= 2*PSMTPS) {
						bp->b_bscto = 0;
						bp->b_state = SNDTTD;
						break;
					}
					x = spl8();
					bp->b_alarm = 1; /* wait 1 tick */
					bp->b_alenb = 1; /* enable alarm */
					splx(x);
					goto closedoor;
				}
				/* buffer full */
				bp->b_bscto = 0;
				bp->b_state = SNDTXT;	/* send what we got */
				if (iflag & BSCASCII) {	/* set up text list*/
					asctxt[0] = (dflag&BSC_XTRN)?
						((dflag&BSC_XSOH)?atsoh:atstx):
						((dflag&BSC_XSOH)?asoh : astx);
#ifdef NBSM
					if (bp->b_lock != SSLOCK) {
						asctxt[1].xnum =
							X_CRC|bsp->bs_size;
						asctxt[1].xptr =
							bsp->bs_buf;
					} else {
#endif
						asctxt[1].xnum =
							X_CRC|bp->b_bsize;
						asctxt[1].xptr =
							bp->b_buffer;
#ifdef NBSM
					}
#endif
					asctxt[2].xnum = (dflag&BSC_XTRN)?1:0;
					asctxt[3] = 
						(dflag&BSC_XLAST)?aetx : aetb;
#ifdef MANCRC
					asctxt[4].xptr = bp->b_crc;
#endif
				} else {
					ebctxt[0] = (dflag&BSC_XTRN)?
						((dflag&BSC_XSOH)?etsoh:etstx):
						((dflag&BSC_XSOH)?esoh : estx);
#ifdef NBSM
					if (bp->b_lock != SSLOCK) {
						ebctxt[1].xnum =
							X_CRC|bsp->bs_size;
						ebctxt[1].xptr =
							bsp->bs_buf;
					} else {
#endif
						ebctxt[1].xnum =
							X_CRC|bp->b_bsize;
						ebctxt[1].xptr =
							bp->b_buffer;
#ifdef NBSM
					}
#endif
					ebctxt[2].xnum = (dflag&BSC_XTRN)?1:0;
					ebctxt[3] = 
						(dflag&BSC_XLAST)?eetx : eetb;
#ifdef MANCRC
					ebctxt[4].xptr = bp->b_crc;
#endif
				}
				break;

			case D_RGTACK:
				if (bp->b_class1 == ((iflag&BSC_ACK)?C_AK1:C_AK0))
					bp->b_state = XFLIP;
				else
					bp->b_state =
					(++bp->b_tmperr >
					 (bp->b_iocin.b_nretry&0xff))
					? RTYERR : WNGACK;
				break;

			case D_XFLIP:
				++bp->b_iocout.b_blks;	/* tally # blks sent */
				bp->b_tmperr = 0;	/* zero tmp error ct */
				bp->b_hlflgs ^= BSC_ACK;
#ifdef NBSM
				if (bp->b_lock != SSLOCK) {
					bsp->bs_flags &= ~BS_FULL;
					wakeup ((caddr_t)&bsp->bs_flags);
				} else {
#endif
					bp->b_hlflgs &= ~BSC_FULL;
					wakeup ((caddr_t)bp->b_buffer);
#ifdef NBSM
				}
#endif
				bp->b_state = (dflag & BSC_XLAST)? DONE : CKXMIT;
				break;

			case D_FASTACK:
				/* Fast acknowledge (text reply to text).
				 * Wait for write caller to finish
				 * as indicated by LAST flag going
				 * off. Wait up to 5 seconds.
				 * When done, go check bcc on text.
				 */
				if (bp->b_alarm <= -100) {	/* Timeout. */
					if (dflag & BSC_XLAST	/* waiting on*/
								/* end of wrt*/
						&& ++bp->b_bscto <= 5*PSMTPS) {
					x = spl8();
					bp->b_alarm = 1;
					bp->b_alenb = 1;
					splx(x);
					goto closedoor;
					}
					bp->b_bscto = 0;
					bp->b_state = CKBCC;	/* done write*/
#ifdef  NBSM
   					if (bp->b_lock != SSLOCK)
                                            bsp->bs_mode = BS_READ;
					else
#endif
                                            bp->b_mode = BS_READ;
					break;
				}
				/* 1st time thru -- terminate write */
				bp->b_tmperr = 0;
				++bp->b_iocout.b_blks;
				bp->b_mode = BSC_IDLE;
#ifdef NBSM
				if (bp->b_lock != SSLOCK) {
					bsp->bs_mode = BS_IDLE;
					bsp->bs_flags &= ~BS_FULL;
					wakeup ((caddr_t)&bsp->bs_flags);
				} else{
#endif
					bp->b_hlflgs &= ~BSC_FULL;
					wakeup ((caddr_t)bp->b_buffer);
#ifdef NBSM
				}
#endif
				bp->b_hlflgs |= BSC_ACK;
				x = spl8();
				bp->b_alarm = 1;
				bp->b_alenb = 1;
				splx(x);
				goto closedoor;

			case D_CKNRTY:
				++bp->b_iocout.b_nretry; /* tally retries */
				bp->b_state =
					(++bp->b_tmperr >
					 (bp->b_iocin.b_nretry&0xff))?
					RTYERR:SNDTXT;
				break;

			case D_CKNWAK:
				++bp->b_iocout.b_nwack; /* tally wacks */
				bp->b_state =
					(++bp->b_tmperr >
					 (bp->b_iocin.b_nwack&0xff))?
					WAKERR:WNGACK;
				break;

			case D_CHKRVI:
				bp->b_state = (iflag&BSCRVIABT)? RVIERR : XFLIP;
				break;

			case D_CORACK:
				bp->b_state = (bp->b_class1==
					       ((iflag&BSC_ACK)?C_AK1:C_AK0))
						? XFLIP : SNDTXT;
				break;

			case D_CKNRT2:
				++bp->b_iocout.b_nretry; /* tally retries */
				bp->b_state =
					(++bp->b_tmperr >
					 (bp->b_iocin.b_nretry&0xff))?
					RTYERR:RTOENQ;
				break;

			case D_CKNBID:
				++bp->b_iocout.b_nbid;
				if (!(iflag & BSCPRIM) &&
				    bp->b_class1 == C_ENQ) {
					bp->b_state = CONTND;
					break;
				}
				if (bp->b_iocin.b_nbid == 0 ||
				    (bp->b_iocin.b_nbid&0xff) >
				     ++bp->b_tmperr) {
					bp->b_state = SNDBID;
					break;
				}
				bp->b_state = BIDERR;
				break;

			case F_SETODD:
				if (!(iflag & BSCMPT))
					bp->b_iocin.b_termid[0] = '\0';
				bp->b_hlflgs |= BSC_ACK;
				asclst[0].xptr = aack0.xptr;
				ebclst[0].xptr = eack0.xptr;
				bp->b_rdflag = 0;	/* reset idle t/o */
#ifdef NBSM
				if (bp->b_lock != SSLOCK)	/* m/station*/
					bsp->bs_rdflg = 0;
#endif
				break;

			case F_SETLST:
				/* Set ebclst or asclst to point to proper
				 * acknowledgement message (even/odd)
				 */
				if (iflag & BSC_ACK) {	/* next msg odd	*/
					/* Response to last should be ACK0 */
					asclst[0].xptr = aack0.xptr;
					ebclst[0].xptr = eack0.xptr;
				} else {		/* next msg even */
					/* Response to last should be ACK1 */
					asclst[0].xptr = aack1.xptr;
					ebclst[0].xptr = eack1.xptr;
				}
				break;

			case D_CKRDY:
				/* If buffer available,
				 * send acknowledgement.
				 * Otherwise, wait up to 2 seconds for it to
				 * become available. If no luck, DELAY.
				 */
				if ( (bp->b_lock == SSLOCK &&
				      bp->b_mode == BSC_WRITE &&
				      (bp->b_sema & BSC_FACK)) ||
				     (bp->b_lock != SSLOCK &&
				      bsp->bs_mode == BS_WRITE &&
				      (bsp->bs_sema & BSC_FACK)) ) {
					bp->b_hlflgs |= BSC_ACK;
					bp->b_state = CKXMIT;
					bp->b_bscto = 0;
					break;
				}
				if (!(dflag & BSC_FULL)) {
					bp->b_state = SETLST;
					bp->b_bscto = 0;
					break;
				}
				if (bp->b_alarm <= -100 &&
				    ++bp->b_bscto >= TWAIT*PSMTPS) {/*time out*/
					bp->b_bscto = 0;
					bp->b_state = DELAY;
					break;
				}
				x = spl8();
				bp->b_alarm = 1;	/* pause a tick */
				bp->b_alenb = 1;	/* enable alarm */
				splx(x);
				goto closedoor;

			/* Check text response.
			 * If CRC error or overrun (block too big), send a NAK,
			 * unless we've already sent the limit, in which case
			 * go to error state NAKERR or TOOBIG.
			 * For no error case, count blocks, set response xmit
			 * list element, flip even/odd indicator, new state is
			 * CKRDY. Also mark buffer full and possibly last (if
			 * received ETX). Wake sleepers.
			 */
			case D_CKBCC:
				if ((iflag & BSC_CRCERR) ||
				    (bp->b_bsize > BSCMBLK)) {
					++bp->b_iocout.b_nnak;
					bp->b_hlflgs &= ~BSC_CRCERR;
					bp->b_state = SNDNAK;
					if (++bp->b_tmperr >
					    (bp->b_iocin.b_nnak&0xff))
						bp->b_state =
							(bp->b_bsize > BSCMBLK)?
							TOOBIG : NAKERR;
					break;
				}
				bp->b_tmperr = 0;	/* reset err cnt*/
				++bp->b_iocout.b_blks;	/* count blocks	*/
				bp->b_state = CKRDY;
				bp->b_hlflgs ^= BSC_ACK;
				bp->b_hlflgs |= BSC_FULL;
				if (iflag & BSC_XTRN)	/* transp.?	*/
#ifdef NBSM
					if (bp->b_lock != SSLOCK)
						bsp->bs_err = BSCTXP;
					else
#endif
						bp->b_iocout.b_flags = BSCTXP;
#ifdef NBSM
				if (bp->b_lock != SSLOCK) {
					if (bsp->bs_mode == BS_FREE) {
						bp->b_hlflgs &= ~BSC_FULL;
						break;
					}
					bsp->bs_flags |= BS_FULL;
					wakeup ((caddr_t)&bsp->bs_flags);
					break;
				}
#endif
				wakeup ((caddr_t)bp->b_buffer);
				break;

			case D_CKNTTD:
				++bp->b_iocout.b_nttd;
				bp->b_state =
					(++bp->b_tmperr >
					 (bp->b_iocin.b_nttd&0xff))?
					TTDERR:SNDNAK;
				break;

			case D_CKABTM:
				bp->b_state = RDONE;
#ifdef NBSM
				if (bp->b_lock != SSLOCK && bsp &&
				    bsp->bs_mode == BS_FREE)
					break;
#endif
				bp->b_hlflgs |= BSC_XLAST;
				if (bp->b_lock != SSLOCK && bsp) {
					bsp->bs_flags |= BS_LAST;
					wakeup ((caddr_t)&bsp->bs_flags);
					break;
				}
				wakeup ((caddr_t)bp->b_buffer);
				break;

			case D_CKMPT:
				if (bp->b_mode == BSC_CLOSED)
					goto closedoor;
				if (bp->b_class1 == C_EOT) {	/* oops */
					bp->b_hlflgs |= BSC_POLLWT;
					bp->b_state = MPT;
					break;
				}
				/* First, check out validity		*/
				/* First two characters must be same,	*/
				/* Next two must also, 			*/
				/* And first two must be our poll or	*/
				/* select address			*/
				if ((bp->b_iocout.b_hostid[0] !=
				     bp->b_iocout.b_hostid[1]) ||
				    ((bp->b_iocout.b_hostid[0] !=
				      bp->b_iocin.b_termid[0]) &&
				     (bp->b_iocout.b_hostid[0] !=
				      bp->b_iocin.b_termid[1])) ||
				    (bp->b_iocout.b_hostid[2] !=
				     bp->b_iocout.b_hostid[3])) {
					/* Not our address, or invalid */
					bp->b_hlflgs |= BSC_POLLWT;
					bp->b_state = MPT;
					break;
				}
				/* Check subdevice address */
				if (bp->b_iocout.b_hostid[2] ==
				    ((iflag&BSCASCII)?0x22:0x7f)) {
					/* general poll */
#ifdef NBSM
					if (bp->b_lock != SSLOCK) {
						for (bsp = bscsubs[dev];
						    bsp < &bscsubs[dev][NBSSUB];
						     ++bsp) {
							if (bsp->bs_mode ==
							    BS_WRITE)
								goto gotone;
						}
						/* Gen Poll, nothing ready */
						bp->b_hlflgs |= BSC_POLLWT;
						bp->b_state = POLEOT;
						break;
					}
#endif
					goto gottwo;
				}
				/* not general poll ... check specific */
#ifdef NBSM
				if (bp->b_lock == SSLOCK) {
#endif
					if(bp->b_iocout.b_hostid[2] ==
					    ((iflag&BSCASCII)?
						0x20:0x40))
						goto gottwo;
#ifdef NBSM
				} else {
			    	    for (x = 0;
				         x < NBSSUB; ++x)
					    if (bp->b_iocout.b_hostid[2] ==
					        ((iflag&BSCASCII)?
						    ascdev:ebcdev)[x]) {
						    bsp = &bscsubs[dev][x];
						    goto gotone;
					    }
				}
#endif
				/* don't have that device */
				bp->b_hlflgs |= BSC_POLLWT;
				bp->b_state = POLEOT;
				break;

#ifdef NBSM
gotone:				bp->b_psmbsy = bsp - bscsubs[dev];
				dflag = bsp->bs_flags;
#endif
				/* Are we being Polled? */
gottwo:
				if (bp->b_iocout.b_hostid[0] ==
				    bp->b_iocin.b_termid[0]) {	/* Poll? */
#ifdef NBSM
					if ((bp->b_lock != SSLOCK &&
					    bsp->bs_mode == BS_WRITE) ||
					    (bp->b_lock == SSLOCK &&
					    bp->b_mode == BSC_WRITE)) {
						if (bp->b_lock != SSLOCK) {
							bsp->bs_sema &=
								~BSC_PDONE;
							bsp->bs_sema |=
								BSC_PBUSY;
						}
#else
					if (bp->b_mode == BSC_WRITE) {
#endif
						/* Polled, ready to send */
						bp->b_sema &= ~BSC_PDONE;
						bp->b_sema |= BSC_PBUSY;
						bp->b_state = CKXMIT;
						bp->b_hlflgs |= BSC_ACK;
						bp->b_hlflgs &= ~BSC_POLLWT;
					} else {
						/* Polled, not ready */
						bp->b_hlflgs |= BSC_POLLWT;
						bp->b_state = POLEOT;
						bp->b_psmbsy = -1;
					}
					break;
				}
				/* Otherwise, we've been selected */
#ifdef NBSM
				if ((!(bp->b_hlflgs & BSC_FULL)) &&
			    	    (bp->b_lock != SSLOCK &&
				     bsp->bs_mode != BS_WRITE) ||
				    (bp->b_lock == SSLOCK &&
				      (bp->b_mode == BSC_READ ||
				       bp->b_mode == BSC_IDLE))) {
					if (bp->b_lock != SSLOCK) {
						bsp->bs_sema &= ~BSC_PDONE;
						bsp->bs_sema |= BSC_PBUSY;
					}
#else
				if ((!(bp->b_hlflgs & BSC_FULL)) &&
				    (bp->b_mode == BSC_IDLE ||
				    bp->b_mode == BSC_READ)) {
#endif
					bp->b_sema &= ~BSC_PDONE;
					bp->b_sema |= BSC_PBUSY;
					bp->b_state = SETODD;
					bp->b_hlflgs &= ~BSC_POLLWT;
#ifdef NBSM
					if (bp->b_lock != SSLOCK) {
						if (bsp->bs_mode != BS_FREE)
							bsp->bs_mode = BS_READ;
					} else
#endif
						bp->b_mode = BSC_READ;
				} else {	/* Write Contention */
					bp->b_hlflgs |= BSC_POLLWT;
					bp->b_state = MPTCNT;
					bp->b_psmbsy = -1;
				}
				break;

                        default: panic("bsc: unknown function#\n");
			}
			break;

		case 's':	/* transmit */
			{
			register struct xlist *xp;

			xp = ((bp->b_hlflgs&BSCASCII)?asclist:ebclist)
				[st->s_ord];
			bp->b_txlst[1] = xp[0];
			bp->b_txlst[2] = xp[1];
			bp->b_txlst[3] = xp[2];
			bp->b_txlst[4] = xp[3];
			bp->b_txlst[5] = xp[4];
			bp->b_txlst[6] = xp[5];
			if (bp->b_trace > 1)
				btxtrc(dev, xp, bp->b_state);
			bscxmit (dev, (int)st->s_next);	/*send list */
			/* b_state will be updated at end of xmit */
			if (states[st->s_next].s_type == 'r')
				bp->b_rclptr = rlist[states[st->s_next].s_ord];
			x = spl8();		/* set the alarm clock */
			bp->b_alarm = ((st->s_ord == X_TXT)?BSCMBLK/300 + 2:
					2)*PSMTPS;
			bp->b_alenb = 1;	/* enable the alarm clock */
			splx(x);
			goto closedoor;
			}

		case 'r':	/* receive */
			/* 1. Set receive list pointer.
			 * 2. Set alarm for 4 seconds
			 *    The alarm will set the new state to st->s_next.
			 */
			bp->b_rclptr = rlist[st->s_ord];
			x = spl8();
			bp->b_alarm = 4*PSMTPS;
			bp->b_alenb = 1;	/* enable clock */
			splx(x);
			/* b_state will be updated at end of receive */
			goto closedoor;

		case 'e':	/* error! */
			/*
			 * 1. Wake any process waiting on the buffer.
			 * 2. If error given, set error bit and save
			 *    error number.
			 * 3. Select next state from s_next.
			 */
#ifdef NBSM
			if (bp->b_lock != SSLOCK && bsp)
				wakeup ((caddr_t)&bsp->bs_flags);
			else
#endif
				wakeup ((caddr_t)bp->b_buffer);

			if (bp->b_mode >= BSC_CL1) {	/* closing */
				bp->b_state = START;
				break;
			}

			if (st->s_ord) {	/* if error given, */
#ifdef NBSM
				if (bp->b_lock != SSLOCK && bsp) {
					bsp->bs_flags &= ~BS_FULL;
					bsp->bs_flags |= BS_ERR;/* set err */
					bsp->bs_err = st->s_ord;
				} else {
#endif
					bp->b_hlflgs &= ~BSC_FULL;
					bp->b_hlflgs |= BSC_ERR;/* set err */
					bp->b_iocout.b_flags = st->s_ord;
#ifdef NBSM
				}
#endif
			}
			bp->b_state = st->s_next;	/* select next state */
			break;

		default:
                        panic ("bsc: unknown state type!\n");
		}
	};
closedoor:	/* Unlock door and leave */
	bp->b_sema &= ~BSC_INPSM;
}

bscpto (dev)	/* process timeout */
caddr_t dev;
{
	register struct bsc *bp;
	register struct state *st;
	register struct bscsub *bpsub;
	register int i;

	bp = &bsc[(dev_t)dev];		/* current dev info */
	st = &states[bp->b_state];	/* current state entry */

	if (bp->b_mode == BSC_CLOSED)	/* closed - no further actions! */
		return;
	if (bp->b_sema & BSC_INPSM) {	/* PSM running? */
		goto out;
	}

	bsckdsr((dev_t)dev,bp);		/* local chk for DSR */
	if (!(bp->b_hlflgs & BSC_DSR)) {
#ifdef NBSM
		if (bp->b_lock != SSLOCK) {
			for (i=0; i < NBSSUB; i++) {
				bpsub = &bscsubs[(dev_t)dev][i];
				bpsub->bs_flags |= BS_ERR;
				bpsub->bs_flags &= ~BS_FULL;
				bpsub->bs_err = BSCNDSR;
				wakeup ((caddr_t)&bpsub->bs_flags);
			}
			goto out;
		}
#endif
		bp->b_hlflgs |= BSC_ERR;
		bp->b_hlflgs &= ~BSC_FULL;
		bp->b_iocout.b_flags = BSCNDSR;
		wakeup ((caddr_t)bp->b_buffer);
		goto out;
	}

	/* check for rd idle timeout */
#ifdef NBSM
	if(bp->b_lock != SSLOCK){
		for(i=0;i<NBSSUB;i++){
			bpsub = &bscsubs[(dev_t)dev][i];
			if(bpsub->bs_mode == BS_READ && bpsub->bs_rdflg && 
				--bpsub->bs_rdflg == 0 ){
				bpsub->bs_err = BSCRXTO;
				bpsub->bs_flags |= BS_ERR;
				bpsub->bs_mode = BS_IDLE;
				wakeup ((caddr_t)&bpsub->bs_flags);
				goto done;
			}
		}
	} else {
#endif
	if (bp->b_rdflag && --bp->b_rdflag == 0 && bp->b_mode == BSC_READ) {
		bp->b_rclptr = 0;		/* reset receiver */
		brxres((dev_t)dev);
		bp->b_iocout.b_flags = BSCRXTO;	/* read timeout */
		bp->b_mode = BSC_IDLE;		/* error state, idle mode */
		bp->b_hlflgs |= BSC_ERR;
		bp->b_state = START;
		wakeup ((caddr_t)bp->b_buffer);
		goto done;
	}
#ifdef NBSM
	}
#endif
	if ((!bp->b_alenb) || (--(bp->b_alarm) > 0)) {
		/* alarm has yet to go off - sleep */
		goto out;
	}
	bp->b_alenb = 0;		/* disable alarm */

	switch (st->s_type) {		/* what to do depends on state */
	case 's':			/* send time out ... modem dead! */
		bp->b_state = XTO;	/* set state to xmit timeout */
		break;

	case 'r':			/* receive timeout - take s_next */
		if (bp->b_trace)	/* if tracing, show rcv t/o */
			bsctr ((dev_t)dev, C_RTO, 'c');	/* reCv'd TimeOut */
		bp->b_state = st->s_next;	/* timeout state */
		bp->b_class1 = C_RTO;	/* timeout data class */
		bp->b_rclptr = 0;	/* reset receiver */
		brxres((dev_t)dev);
		break;

	case 'd':			/* function delay */
		bp->b_alarm = -100;	/* indicate second time through */
		break;

	default:
                panic ("bsc: timeout in unknown state!\n");
		break;
	}
done:
	bscpsm ((dev_t)dev);			/* restart processing */

out:	/* set up next call to bscpto */
	timeout (bscpto, dev, PSMTICK);	/* timeout again */
}

/*
 *	Compare two strings -- return zero if match, non-zero if fail
 */
bsccmp(s1,s2)
register char *s1, *s2;
{
	while (*s1)
		if (*s1++ != *s2++)
			return 1;
	return (int) *s2;
}

/*
 * NAME
 *	btxtrc - trace tx data
 * SYNOPSIS
 *	btxtrc(dev,xlptr,state)
 *	dev_t dev;
 *	int state;
 *	struct xlist *xlptr;
 * ALGORITHM
 *	For each transmit list element, call bsctr to trace the
 *	transmit data (type is 'x'; supply xlen and xptr)
 */
btxtrc(dev,xlptr,state)
register dev_t dev;
register int state;
register struct xlist *xlptr;
{
	while (xlptr->xptr) {
		bsctr(dev,state,'x',(short)xlptr->xnum,xlptr->xptr);
		++xlptr;
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.