BBN-Vax-TCP/stand/d2dcpy.c

Compare this file to the similar file:
Show the results in this format:

# define RP6CYL  815  /*  no. RP06 cylinders/pack */
# define RP6TRK  19  /*  no. tracks/cyl  */
# define RP6SEC  22  /*  no. sectors/track  */
# define RP6ST  (rptrk*rpsec)  /*  no. sectors/cyl  */
# define MAXSEC  (rpcyl*rptrk*rpsec)  /*  sectors/pack  */
# define M0  0x20010000  /* phys addr MBA 0  */
# define M_st  2  /*  offset for MBA status reg */
# define M0_cr  (M0+4)  /*  MBA 0 control reg addr */
# define M0_map  (M0+0x800)  /* start MBA 0 map reg's */
# define M0_var  (M0+0xc)  /* MBA 0 virt addr reg */
# define M0_bc  (M0+0x10)  /*  MBA 0 byte count reg */
# define MBAinit 01  /*  MBA init bit */
# define M_DTC  0x2000  /* Data Transfer Complete */
/*		*/
# define RP  (M0+0x400)  /*  base for RP06 reg's, drive 0  */
/*		*/
# define RP_cr  0  /* RP06 control reg offset, longword */
# define RP_sr  1  /*  RP06 status reg offset */
# define RP_er1  2  /*  RP06 error reg 1 */
# define RP_stk  5  /*  RP06 sector/track reg offset */
# define RP_typ  06  /*  disk type reg */
# define RP_off  011  /*  RP offset reg */
# define RP_cyl  10  /*  RP06 cylinder reg offset */
# define RP_Epos 016  /*  RP ECC position reg */
# define RP_Epat 017  /*  RP ECC pattern reg */
/*		*/
# define RP_GO  1  /*  go bit */
# define RP_RD	070	/* RP06 read function code */
# define RP_WR  060  /*  RP06 write function code */
# define RP_DC  010  /*  drive clear function code */
# define RP_FMT  0x1000  /*  format bit in RP offset reg */
# define RP_RIP  020  /*  Read-in Preset function code */
# define RP_MOL  0x1000  /*  medium online bit in status */
# define RP_DRY  0200  /*  drive ready, status reg */
# define RP_ERR 040000  /* composite error, status reg */
# define RP_DCK  0x8000  /*  Data Check Error in ERR1 reg */
# define RP_ECH  0x40  /*  ECC hard error */
/*		*/
# define RXCS	32  /*  receiver control/staus */
# define RXDB  33  /*  receiver data */
# define TXCS  34  /*  transmitter control/status */
# define TXDB  35  /*  transmitter data */
# define RXCS_DONE  0x80  /*  receiver done */
# define TXCS_RDY  0x80  /*  transmitter ready */
/*		*/
# define BLKSIZ 512
# define NB 128  /*  max. byte transfer = 64K bytes */
# define BUFSIZ (NB*BLKSIZ)
# define MAXUNI  1
# define MAXERR 10  /*  max. no. i/o errors allowed */
# define NL  012
# define CR 015
# define CDEL  0x23
# define LDEL  0x40
/*		*/
# define RM3CYL  823  /* RM03 */
# define RM3TRK  5
# define RM3SEC  32
# define RP6typ  022
# define RM3typ  024
 
struct { int reg ; } ;
int dinoff , douoff  , dblks , count  , ecount , daterr ;
char *bufptr ;
unsigned int page ;
int *RPin , *RPout ;
int rpsec,rptrk,rpcyl;
char input[132] ;
 
main() {
/*
*  Stand-alone program to copy rp06/RM03 disk to rp06/RM03 disk, same or
*  different drives. User specifies input and output disk, no.
*  of 512-byte blocks, and disk offsets.
*/
register int i , error ;

putlin("d2dcpy : Disk-to-Disk Copy") ;
putnl() ;
 
d1u :
 
putstr("input disk unit : ") ;
getcon(input) ;
i = a2l(input) ;
if (i < 0) goto fini ;
if (i > MAXUNI) goto d1u ;
RPin = RP + (i * 32 * 4) ;
 
dof1 :
 
putstr("offset : ") ;
getcon(input) ;
dinoff = a2l(input) ;
 
d2u :
 
putstr("output disk unit : ") ;
getcon(input) ;
i = a2l(input) ;
if ((i > MAXUNI) || (i < 0)) goto d2u ;
RPout = RP + (i * 32 * 4) ;
 
dof2 :
 
putstr("offset : ") ;
getcon(input) ;
douoff = a2l(input) ;
 
gknt :
 
putstr("no. 512-byte blocks : ") ;
getcon(input) ;
count = a2l(input) ;
 
error = 0 ;
 
if (init()) {
	putlin("init error") ;
	goto d1u ;
	}
 
if ((dinoff < 0) || (dinoff > MAXSEC-1)) goto dof1 ;
if ((douoff < 0) || (douoff > MAXSEC-1)) goto dof2 ;
if (count < 0) goto gknt ;
if (count == 0) count = MAXSEC ;
 
ecount = daterr = 0 ;
while ((error == 0) && (count>0)) {
	if (dread()) {
		dioerr :
			putlin("disc i/o error") ;
			error++ ;
			continue ;
			}
	if (dwrite()) goto dioerr ;
	count -= dblks ;/*  dec no. blocks read */
	}
 
fini :
 
putstr("# Data Check Errors : ") ;
l2x(daterr,input) ;
putlin(input) ;
putstr("# Other errors : ") ;
l2x(ecount,input) ;
putlin(input) ;
 
return(0) ;
}
 
/*		*/
 
putstr(csp)
register char *csp ;
{
if (putcon(csp)) return(-1) ;
return(0) ;
}
 
/*		*/
 
putlin(sptr)
register char *sptr ;
{
if (putcon(sptr)) return(-1) ;
if (putnl()) return(-1) ;
return(0) ;
}
 
/*		*/
 
putnl()
{
if (putcon("\r\n")) return(-1) ;
return(0) ;
}
 
/*		*/
 
putcon(csp)
register char *csp ;
{
/*
*  Function to output null-terminated string pointed to 
*  by 'csp' to the VAX LSI terminal.
*/
register c ;
 
c = 0 ;
while (c = (*csp++)) putc(c) ;
return(0) ;
}
 
/*		*/
 
putc(c)
{
/*  wait for LSI printer to be ready */
while ((mfpr(TXCS) & TXCS_RDY) == 0) ;
/*  output character */
mtpr(TXDB,c&0177) ;
}
 
/*		*/
 
getcon(cs)
register char *cs ;
{
/*
*  Function to return char's from VAX LSI keyboard to
*  char array 'cs' - input stops when CR or LF received -
*  null char appended to end of input
*/
register int c , c2 ;
int getc() ;
char *ocs;
 
	ocs=cs;
inloop :
	c = getc() ; /* get 1 char from terminal */
	putc(c) ;  /*  echo char */
	if (c==CDEL) { --cs; goto inloop; }
	if (c==LDEL){ putc(NL);putc(0);putc(CR);cs=ocs;goto inloop;}
	if ((c == NL) || (c == CR)) {
		putc(CR) ;
		putc(0) ;
		putc(NL) ;
		(*cs++) = '\0' ;
		return(0) ;
		}
	else {
		(*cs++) = c ;
		goto inloop ;
		}
}
 
/*		*/
 
getc()
{
/*
*  Return char from VAX LSI terminal char buffer
*/
int mfpr() ;
 
/*  Wait for receiver done (user entered char)
*/
while ((mfpr(RXCS) & RXCS_DONE) == 0) ;
return (mfpr(RXDB) & 0177) ;  /* return char from receiver buffer */
}
 
/*		*/
 
mtpr(regno,value)
{
	asm("	mtpr	8(ap),4(ap)") ;
}
 
/*		*/
 
mfpr(regno)
{
	asm("	mfpr	4(ap),r0") ;
}
 
/*		*/
 
a2l(as)
register char *as ;
{
/*
*  Convert null-terminated ascii string to binary
*  and return value.
*  1st char in string :
*	0 -> octal
*	x -> hex
*	else decimal
*/
register value , base , sign , digit ;
 
digit = value = sign = 0 ;
base = 10 ;  /* default base */
 
aloop :
if ((digit = (*as++)) == 0) return(value) ; /* null */
 
if (digit == '-') {
	sign++ ;
	goto aloop ;
	}
 
if (digit == '0') base = 8 ;  /* octal base  */
else { if (digit == 'x') base = 16 ;  /* hex base */
	else value = (digit-060) ; /* 060 = '0' */
	}
 
while (digit = (*as++)) {
	if (digit < '0') return(0) ;
	switch (base) {
		case 8 : {
			if (digit > '7') return(0) ;
			digit -= 060 ;
			break ;
			}
		case 10 : {
			if (digit > '9') return(0) ;
			digit -= 060 ;
			break ;
			}
		case 16 : {
			if (digit <= '9') {
				digit -= 060 ;
				break ;
				}
			if ((digit >= 'A') && (digit <= 'F')) {
				digit = (digit - 0101 + 10) ;
					break ;
				}
			if ((digit >= 'a') && (digit <= 'f')) {
				digit = digit - 0141 + 10 ;
				break ;
				}
			return(0) ;
			break ;
			}
		}
	value = (value * base) + digit ;
	}
return (sign ? -value : value) ;
}
 
/*		*/
 
init() {
/*
*  Initialization.
*  Initialize MBA 0 for disk i/o.
*  Set up MBA 0 map registers to map a max.
*    transfer of 'BUFSIZ' bytes.
*/
register int *mp0 , i ;
extern char *end ;
 
M0_cr->reg = MBAinit ;
dblks = BUFSIZ/BLKSIZ ; /* no. of disk blocks / input buffer */
 
if ((*(RPin+RP_sr) & RP_MOL) == 0) {
	putlin("input unit not online") ;
	return(-1) ;
	}
 
*(RPin+RP_cr) = RP_RIP | RP_GO ; /* preset */
*(RPin+RP_off) = RP_FMT ; /* set format bit */
 
if (RPin != RPout) {
	if ((*(RPout + RP_sr) & RP_MOL) == 0) {
		putlin("output unit not online") ;
		return(-1) ;
		}
	*(RPout+RP_cr) = RP_RIP | RP_GO ;
	*(RPout+RP_off) = RP_FMT ;
	}
 
i = *(RPout+RP_typ)&0777 ;  /* get disk type */
if (i==RP6typ) { /* RP06 */
	rpsec=RP6SEC; rpcyl=RP6CYL; rptrk=RP6TRK;
	}
else {
	if (i==RM3typ) {
		rpsec=RM3SEC; rpcyl=RM3CYL; rptrk=RM3TRK;
		}
	else return(-1);
	}
 
bufptr = (int)(&end + 511) & 017777777000 ;
page = (int)((int)bufptr>>9) & 017777777 ;
mp0 = M0_map ; /* phys addr of MBA 0 map reg base */
 
i = NB ;
 
while (i--)
	(*mp0++)= 0x80000000 | page++ ; /* map entry */

return(0);
}
 
/*		*/
 
dread()
{
/*
*  Function to read 'BUFSIZ' bytes (512 multiple) from disc
*  to buffer .
*/
register int i , j ;
 
*(RPin+RP_cyl) = dinoff/RP6ST ; /* cylinder no. */
i = dinoff%RP6ST ;
j = (i/rpsec)<<8 ; /* track */
*(RPin+RP_stk) = j | (i%rpsec) ; /* sector : track */
dinoff += dblks ;  /*  point to next disc sector */
M0_bc->reg = (count<dblks?-(count*512):(-BUFSIZ)) ; /* byte count */
M0_var->reg = 0 ; /* virt addr reg = map no. + byte off */
rbit :
*(RPin+RP_cr) = RP_DC | RP_GO ; /* drive clear */
dwait(RPin) ;
*(RPin+RP_cr) = RP_RD | RP_GO ; /* read */
 
dwait(RPin) ; /* wait for i/o to finish */
if (i = mbaerr(M0)) {
	/* don't abort on MBA errors - 'mbaerr()' has cleared
	MBA status reg */
    }
 
if (i = derror(RPin)) { /*  error  */
	putlin("- - - - - -") ;
	putstr("read error") ;
	stmes(i) ;
	dadmes(RPin) ;
	if (i & RP_DCK) { /* Data Check Error */
		daterr++ ;
		putlin("Data Check") ;
		if (i & RP_ECH) { /*  ECC Hard Error */
			putlin("ECC non-recov") ;
			ecount++ ;
			}
		else { /*  ECC Recoverable */
			ECCrcv(RPin) ;
			}
		if (M0_bc->reg) { /* more i-o to finish ? */
			j = (*(RPin+RP_stk));
			i = (j>>8) & 0x1f;
			j = j & 0x1f;
			if (j>=rpsec) /*sector */
				j = 0;
			if (i>=rptrk) /* track */
				i = 0;
			*(RPin+RP_stk) = (i<<8) | j;
			goto rbit ; /* staus reg cleared by 'Drive Clear' */
			}
		else {
		*(RPin+RP_cr) = RP_DC | RP_GO;
			mbaerr(M0);
			}
		}
	else { /* non-Data Check error */
		ecount++ ;
		}
	if (ecount > MAXERR) return(-1) ;
	}
return(0) ; /* normal return */
}
 
/*		*/
 
dwrite()
{
/*
*  Function to write 'BUFSIZ' bytes (512 multiple) to disc
*  from buffer .
*/
register int i , j ;
 
*(RPout+RP_cr) = RP_DC | RP_GO ;
*(RPout+RP_cyl) = douoff/RP6ST;
i = douoff%RP6ST ;
j = (i/rpsec)<<8 ; /* track */
*(RPout+RP_stk) = j | (i%rpsec) ; /* sector : track */
M0_bc->reg = (count<dblks?-(count*512):(-BUFSIZ)) ; /* byte count */
M0_var->reg = 0 ; /* virt addr reg = map no. + byte off */
*(RPout+RP_cr) = RP_WR | RP_GO ; /* write */
 
douoff += dblks ;  /*  point to next disc sector */
dwait(RPout) ; /* wait for i/o to finish */
if (i = mbaerr(M0)) {
  return(-1) ;
  }
if (i = derror(RPout)) {
	putstr("write error") ;
	stmes(i) ;
	dadmes(RPout) ;
	if (++ecount > MAXERR) return(-1) ;
  }
return(0) ; /* normal return */
}
 
/*		*/
 
dwait(dptr)
register int *dptr ;
{
/*
* Function to wait MBA 0 RP06 disc unit to be ready.
*/
while ((*(dptr+RP_sr)&RP_DRY) == 0) ;
}
 
/*		*/
 
derror(dptr)
register int *dptr ;
{
/*
*  Function to check for MBA 0 RP06 error.
*/
if (*(dptr+RP_sr) & RP_ERR) return(*(dptr+RP_er1) & 0177777) ;
return(0) ;
}
 
/*		*/
 
halt()
{
asm("	halt") ;
}
 
/*		*/
 
stmes(code)
int code ;
{
putstr(" : err reg : ") ;
RPE_print(code) ;
}
 
/*		*/
 
dadmes(dptr)
register int *dptr ;
{
register char *mesp ;
register int i ;
 
mesp = " cyl     trk     sec    " ;
i = l2x(*(dptr+RP_cyl) & 01777,&mesp[5]) ;
blnkit(&mesp[5+i],4-i) ;
 
i = l2x((*(dptr+RP_stk)>>8) & 037 , &mesp[13]) ;
blnkit(&mesp[13+i],3-i) ;
 
i = l2x(*(dptr+RP_stk)&037,&mesp[21]) ;
blnkit(&mesp[21+i],3-i) ;
 
putlin(mesp) ;
}
 
/*		*/
 
blnkit(mp,cc)
register char *mp ;
register int cc ;
{
 
while (cc--)
	(*mp++) = ' ' ;
}
 
/*		*/
 
mbaerr(mba)
register int *mba ;
{
register int i ;
 
if ((i = (*(mba+M_st))) != M_DTC) {
	putlin("- - - - - -") ;
	putstr("MBA error : status reg = ") ;
	MBAS_print(i) ;
	*(mba+M_st) = (-1) ;
	return(i) ;
  }
return(0) ;
}
 
/*		*/
 
l2x(val,rptr)
register int val ;
register char *rptr ;
{
register int i , j ;
register char *tp ;
int knt ;
char tmp[20] , sign ;
 
knt = sign = 0 ;
if (val < 0) {
	sign++ ;
	val = (-val) ;
	}
 
tp = tmp ;
loop :
	knt++ ;
	i = val/16  ;  /*  quotient & base 16 */
	j = val%16 ;
	(*tp++) = j + (j<10?0x30:0x57) ;
	val = i ;
	if (val == 0) {
		/*  done  dividing  */
		if (sign) { knt++ ; (*tp++) = '-' ; }
		for (i = knt ; i ; i--)
			(*rptr++) = tmp[i-1] ;
		(*rptr++) = '\0' ;
		return(knt) ;
		}
	else goto loop ;
}
 
/*		*/
 
ECCrcv(dptr)
register int *dptr ;
{
/*
*  Do ECC error recovery on disk whose register set is pointed
*  to by 'dptr'.
*  'mbaerr()' has cleared MBA status reg.
*  With ECC enabled, disk read has stopped after sector with bad
*  data. After correction of data, return to 'dread()' which will
*  continue read of track if more sectors to do.
*  Return 0.
*/
register unsigned int pos , pat ;
register unsigned short *wordp ;
unsigned int ll ;
struct { short wlo , whi ; } ;
char tmp[50] ;
 
pat = (*(dptr+RP_Epat)) & 0xffff ; /* ECC pattern reg */
pos = (*(dptr+RP_Epos)) & 0xffff ; /* ECC position reg */
putstr("pat : ") ;
ul2x(pat,tmp) ;
putlin(tmp) ;
putstr("pos : ") ;
ul2x(pos,tmp) ;
putlin(tmp) ;
wordp = bufptr ;   /* ptr to buffer */
 
/*
*  'BUFSIZ' bytes are read on each read into buffer pointed to
*  by 'bufptr'. MBA byte count reg has neg. no. of bytes remaining
*  in read if this read error was not in the last sector to be
*  read.
*/
/* calculate buffer location of faulty data */
wordp = (char *)wordp + (BUFSIZ + ((M0_bc->reg)>>16) - BLKSIZ) ; /* sector in buffer */
wordp = wordp +  ((pos-1)>>4) ; /* word within sector */
 
/* burst pattern may be across word boundary */
ll = (*wordp) + ((*(wordp+1))<<16) ;
putstr("bad data  : ") ;
ul2x(ll,tmp) ;
putlin(tmp) ;
pat = pat<<((pos%16)-1) ;
ll = ll^pat ; /* correction */
putstr("good data : ") ;
ul2x(ll,tmp) ;
putlin(tmp) ;
 
/* put good data back in buffer */
*wordp = ll.wlo ;
*(wordp+1) = ll.whi ;
 
return(0) ;
}
 
/*		*/
 
ul2x(val,rptr)
register unsigned int val ;
register char *rptr ;
{
register unsigned int i , j ;
register char *tp ;
int knt ;
char tmp[20] ;
unsigned int udiv() , urem() ;
 
knt =  0 ;
 
tp = tmp ;
loop :
	knt++ ;
	/* use unsigned integer divide & remainder routines */
	i = udiv(val,16)  ;  /*  quotient & base 16 */
	j = urem(val,16) ;
	(*tp++) = j + (j<10?0x30:0x57) ;
	val = i ;
	if (val == 0) {
		/*  done  dividing  */
		for (i = knt ; i ; i--)
			(*rptr++) = tmp[i-1] ;
		(*rptr++) = '\0' ;
		return(knt) ;
		}
	else goto loop ;
}