DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦5cd24c4b2⟧ TextFile

    Length: 12456 (0x30a8)
    Types: TextFile
    Notes: UNIX file
    Names: »trw8.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦2d53db1df⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »frankh/format/trw8.c« 

TextFile

/* (-lgl
 * 	The information contained herein is a trade secret of Mark Williams
 * 	Company, and  is confidential information.  It is provided  under a
 * 	license agreement,  and may be  copied or disclosed  only under the
 * 	terms of  that agreement.  Any  reproduction or disclosure  of this
 * 	material without the express written authorization of Mark Williams
 * 	Company or persuant to the license agreement is unlawful.
 * 
 * 	COHERENT Version 0.7.3
 * 	Copyright (c) 1982, 1983, 1984.
 * 	An unpublished work by Mark Williams Company, Chicago.
 * 	All rights reserved.
 -lgl) */
/*
 * Driver for Western Digital hard disk controller for the Z8000HR.
 * 
 * Uses Commodore's SASI-like command block structure.
 * December 3, 1984
 * February 15, 1985 (nrb) added code for new DMA fixes and coditional execution
 * March 14, 1985 (nrb) added code to write pseudo-random paterns on disk
 * March 18, 1985 (nrb) added code for multiple drives & drive params
 * March 21, 1985 (nrb) added grr's code for worst case pattern testing 
 * March 22, 1985 (nrb) added code to select pattern for tests
 */
#define		CMDBLKPADDR	(0x80000L)	/* WD command blk phys addr */
#define		BUFPADDR	(0x80400L)	/* CMDBLKPADDR + 1K */
#define		LONGBUFPADDR	(0xA0000L)	/* CMDBLKPADDR + 128K */
#define		VERS		"V5.2b"		/* version # */

#include	<coherent.h>
#include	<buf.h>
#include	<con.h>
#include	<stat.h>
#include	<uproc.h>
#include	<errno.h>

/*
 * this is to make this file compatable with tmd.s
 */
#undef	WDS
#define	WDS	0x3C
extern	int	errors;
extern	int	timeouts;
extern 	unsigned	pass;
extern	int	badblk;
int	ftload();
int	ftuload();
int	ftopen();
int	ftread();
int	ftwrite();
int	ftblock();
int	ftintr();
int	ftintr1();
int	wdintr();
int	nulldev();
int	nonedev();
char	*pfix();			/* map phys addr to a char * */
int	wfill();			/* fill block w/ test pattern */
int	wcheck();			/* compare data pattern */

CON	wdcon	= {
	DFBLK|DFCHR,			/* Flags */
	6,				/* Major index */
	ftopen,				/* Open */
	nulldev,			/* Close */
	ftblock,			/* Block */
	ftread,				/* Read */
	ftwrite,			/* Write */
	nonedev,			/* Ioctl */
	nulldev,			/* Powerfail */
	nulldev,			/* Timeout */
	ftload,				/* Load */
	ftuload				/* Unload */
};

/*
 * Western Digital Controller port addresses
 */
#define	WDIO	0x0500			/* Data Register (word mode) */

#define	WDTDR	0x00			/* test drive ready */
#define	WDREST	0x01			/* restore to cyl 0 */
#define	WDRSS	0x03			/* Request status */
#define	WDCTF	0x05			/* check track format */
#define	WDFMTT	0x06			/* format track */
#define	WDREAD	0x08			/* Read */
#define	WDWRITE	0x0A			/* Write */
#define	WDSDP	0x0C			/* set drive parameters */
#define	WDCCBA	0x0F			/* change command block address */
#define	WDDDIAG	0xE3			/* run drive diagnostics */
#define	WDCDIAG	0xE4			/* run controller diagnostics */

#define	NSEC	17			/* number of sectors per track */
#define	NTRK	4			/* number of tracks per cylinder */
#define	NCYL	306			/* number of cylinders */
#define	WDIRQ	0x80			/* base of wd interrupt vector */
#define	SIXTEENuS 0xF			/* sixteen microsecond step rate */

typedef	struct	wdcmd {			/* command block layout */
 	unsigned char	c_opcode;	/* command class & opcode */
	unsigned char	c_lunhiaddr;	/* lun [7:5] & sector addr [4:0] */
	unsigned char	c_midaddr;	/* middle sector address */
	unsigned char	c_lowaddr;	/* low part of sector address */
	unsigned char	c_blockcnt;	/* number of blocks in I/O */
	unsigned char	c_control;	/* reserved control byte */
	unsigned char	c_highdma;	/* high DMA addr (phys segment) */
	unsigned char	c_middma;	/* middle DMA address */
	unsigned char	c_lowdma;	/* low DMA address */
	unsigned char	c_rsvd1;	/* reserved */
	unsigned char	c_rsvd2;	/* reserved */
	unsigned char	c_rsvd3;	/* reserved */
	unsigned char	c_errorbits;	/* error information */
	unsigned char	c_lunladd2;	/* error lun and high sector addr */
	unsigned char	c_ladd1;	/* error middle address */
	unsigned char	c_ladd0;	/* error low address */
} WDCMD;

typedef struct	wd_idc_params {		/* drive initialization params */
	unsigned char	p_optstep;	/* options & step rate */
	unsigned char	p_headhicyl;	/* heads <6:4>, hi cyl count <3:0> */
	unsigned char	p_cyl;		/* low byte of cyl count */
	unsigned char	p_precomp;	/* precomp cyl / 16 */
	unsigned char	p_reduce;	/* reduced write current / 16 */
	unsigned char	p_sectors;	/* sectors per track */
	char		*p_devname;	/* device name for user */
	int		p_ntrk;		/* tracks per cylinder */
	int		p_ncyl;		/* number of cylinders */
} WDINFO;

WDINFO	wdinfo[] = {			/* add entries as needed */
	{ SIXTEENuS, (4<<4)|(306/256), 306%256, 128/16, 128/16, NSEC,
	  " 4 head 10MB half-height", 4, 306 },
	{ SIXTEENuS, (4<<4)|(612/256), 612%256, 128/16, 128/16, NSEC,
	  " 4 head 20MB half-height", 4, 612 },
	{ SIXTEENuS, (4<<4)|(10/256), 10%256, 10/16, 10/16, NSEC,
	  "4 head 10 cylinder test disk", 4, 10 },
	{ SIXTEENuS, (7<<4)|(704/256), 704%256, 352/16, 352/16, NSEC,
	  "Atasi 7 head 42MB full-height", 7, 704 }
};

int	wdiflag;			/* interrupt acknowledge flag */
/* int	timeouts;			 number of timeouts */
/* int	errors;				 total # of errors  */

int	typeno;				/* drive type selected from table */
int	patno;				/* pattern selection # */
int	unit;				/* which physical drive ? */
int	nsec;				/* # of sectors per track */
int	ntrk;				/* # of tracks per cylinder */
int	ncyl;				/* # of cylinders */
long	nblk;				/* number of blocks on device */
long	nblkcyl;			/* number of blocks on a cylinder */
int	errsup;				/* suppress error messages */
extern	char	databuf[512];
extern	unsigned char pattern[512];
unsigned int seedy;

/*
 * simple test routine to try and format the hard disk using the new
 * Western Digital controller for the Commodore Z8000HR...
 */
ftload()
{
	register long l;
	register int ans, i;
	register int tfmt, tver, bwrite, bread, rndread;
	register int prwrite, prread, cylread, cylrdwr;
	int	frank;

#ifdef	NOINTERRUPTS
/*	sphi();				 never to be set low again! */
#endif
	unit=0; typeno=0; patno=0; errsup=0;
	tfmt=0; tver=0; bwrite=0; bread=0; rndread=0; cylread=0; cylrdwr=0;
	prwrite=0; prread=0;
	printf("Hard disk diagnostic for WD/Commodore controller, %s\n\n",VERS);

	typeno = 1;
	printf("\n Drive selected: %s\n",wdinfo[typeno].p_devname);

	nsec = wdinfo[typeno].p_sectors;
	ntrk = wdinfo[typeno].p_ntrk;
	ncyl = wdinfo[typeno].p_ncyl;
	nblkcyl = nsec * ntrk;			/* fits in an int */
	nblk = nblkcyl * (long)ncyl;		/* fits in a long */


	unit = 0;
	patno = 1;


	printf("\nDisk parameters: unit=%d sectors=%d heads=%d cylinders=%d\n",
		unit, nsec, ntrk, ncyl);

	++bwrite;
	++bread;



#ifndef	NOINTERRUPTS
	setivec(WDIRQ, ftintr);
#endif
	wdsetparam();
	switch (patno) {
	case 0:
		for (i = 0; i <= 255; ++i)
			pattern[i] = i;
		for (i = 255; i >= 0; --i)
			pattern[511-i] = i;
		break;
	case 2:
		for (i = 0; i < 32; ++i)
			for (ans = 0; ans < 16; ++ans)
				pattern[16*i+ans] = ans;
		break;
	case 3:					/* pattern for Eric */
		for (i=0; i < 256; ++i) {
			pattern[2*i] = 0xFF;	/* data bits 15:8 */
			pattern[2*i+1] = i;
		}
		break;
	case 4:
		for (i = 0; i < 256; ++i) {
			pattern[2*i] = i;
			pattern[2*i+1] = 0xFF;
		}
		break;
	}

testloop:

/*    for (frank = 0; frank < 2 ; ++frank) {	*/


	if (bwrite) {
		printf("Starting write phase\n");
		seedy = 0;
		for (l = 0; l < nblk; ++l)
			ftwrite(l);
	}
	if (bread) {
		printf("Starting read phase\n");
		seedy = 0;
		for (l = 0; l < nblk; ++l)
			ftread(l);
	}

	printf("\n\007Unit %d: pass count = %d, timeouts = %d errors=%d\n",
		unit, ++pass, timeouts, errors);
/*    }		*/

#ifdef	FRANK
	typeno = 3;
#else
	typeno = 1;
#endif
	wdsetparam();
}

ftuload()
{

}

wdwait()
{
	register int s;
	register long l = 1000000L;
#ifdef	NOINTERRUPTS
	register WDCMD *cbp;
	register unsigned i;
#endif

	out(WDIO, 1);				/* strobe I/O line to WD */
#ifdef NOINTERRUPTS
	cbp = (WDCMD *) pfix(WDS, CMDBLKPADDR);
	do {
		i = cbp->c_errorbits;
		--l;
	} while ((i&0xFF) == 0xFF && l);	
#else
	wdiflag = 0;
	s = splo();
	while (!wdiflag && --l > 0)
		;
	spl(s); 
#endif
	if (!l) {
		eprintf("\nTIMEOUT ERROR\n");
		++timeouts; ++errors;
#ifndef	NOINTERRUPTS
	out(WDIO, 0);
#endif
	}
#ifdef	NOINTERRUPTS
	out(WDIO, 0);			/* reset IEO on DMA chip */
#endif
}

wderr(cp)
char *cp;
{
	eprintf("\n%s", cp);
	while (1)
		;
}

#ifdef	NOINTERRUPTS
ftintr1(id)
int id;
{
	out(WDIO, 0);
}
#endif

ftintr(id)
int id;
{
#ifdef	NOINTERRUPTS
	eprintf("ftintr: got a spurious interrupt !!!\n");
	++errors;
#else
	wdiflag++;
	out(WDIO, 0);			/* reset IEO on DMA chip */
#endif
}

ftopen()
{
	eprintf("ftopen: \n");
}

ftread(sn)
long sn;
{
	register int i;
	register WDCMD *cbp;
	register unsigned char *cp;
/*	unsigned char c;		*/

/*	c = sn;				*/
/*	eprintf("%d \r", (int)sn);	*/
	cbp = (WDCMD *) pfix(WDS, CMDBLKPADDR);
	for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
		cp[i] = 0;
	cbp->c_opcode = WDREAD;			/* read a sector */
	cbp->c_blockcnt = 1;
	cbp->c_highdma = (BUFPADDR >> 16);
	cbp->c_middma = (BUFPADDR >> 8);
	cbp->c_lowdma = 0x00;
	cbp->c_lunhiaddr = (unit << 5) | (sn >> 16);
	cbp->c_midaddr = sn >> 8;
	cbp->c_lowaddr = sn;
	cbp->c_errorbits = 0xff;		/* make ready */
	cp = pfix(WDS, BUFPADDR);
	wdblkinit(cp, 0x13);			/* fill with known values */
	wdwait();				/* wait for i/o complete */
	cbp = (WDCMD *) pfix(WDS, CMDBLKPADDR);
	i = cbp->c_errorbits;
	if (i & 0x7F) {
		eprintf("\nread error: block=%p, i=%x\n", sn, i);
		for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
			eprintf("%x ", cp[i]);
		eprintf("\n");
		++errors;
	}
	cp = pfix(WDS, BUFPADDR);
	if (wcheck(cp, sn)) {
		++errors;
	}
}

ftwrite(sn)
long sn;
{
	register int i;
	register WDCMD *cbp;
	register unsigned char *cp;
/*	unsigned char c;		*/

/*	eprintf("%d\r", (int)sn);	*/
/*	c = sn;					 use low byte of sec # */
	cp = pfix(WDS, BUFPADDR);	/* data area */
	wfill(cp);
	cbp = (WDCMD *) pfix(WDS, CMDBLKPADDR);
	for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
		cp[i] = 0;
	cbp->c_opcode = WDWRITE;		/* write a sector */
	cbp->c_blockcnt = 1;
	cbp->c_highdma = (BUFPADDR >> 16);
	cbp->c_middma = (BUFPADDR >> 8);
	cbp->c_lowdma = 0x00;
	cbp->c_lunhiaddr = (unit << 5) | (sn >> 16);
	cbp->c_midaddr = sn >> 8;
	cbp->c_lowaddr = sn;
	cbp->c_errorbits = 0xff;		/* make ready */
	wdwait();				/* wait for i/o complete */
	cbp = (WDCMD *) pfix(WDS, CMDBLKPADDR);
	i = cbp->c_errorbits;
	if (i & 0x7F) {
		eprintf("\nwrite error: block=%p, i=%x\n", sn, i);
		for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
			eprintf("%x ", cp[i]);
		eprintf("\n");
		++errors;
	}
}

ftblock()
{
	eprintf("ftblock:\n");
}

/*
 * initialize the WD controller and clear out the command blocks.
 */
wdsetparam()
{
	register WDCMD *cbp;
	register unsigned char *cp;
	register int i;
	register WDINFO *ip;

	cbp = (WDCMD *) pfix(WDS, CMDBLKPADDR);
	for (cp = cbp, i = 0; i < 2*sizeof(WDCMD); ++i)
		*cp++ = 0;
	cbp->c_opcode = WDSDP;		/* set drive params */
	cbp->c_blockcnt = 0;
	cbp->c_highdma =(LONGBUFPADDR >> 16);
	cbp->c_middma = (LONGBUFPADDR >> 8);
	cbp->c_lowdma = 0x00;
	cbp->c_lunhiaddr = unit << 5;
	cbp->c_midaddr = 0;
	cbp->c_lowaddr = 0;
	cbp->c_errorbits = 0xff;		/* make ready */
	ip = (WDINFO *)pfix(WDS, LONGBUFPADDR);
	*ip = wdinfo[typeno];
	wdwait();				/* wait for i/o complete */
	cbp = (WDCMD *) pfix(WDS, CMDBLKPADDR);
	i = cbp->c_errorbits;
	if (i & 0x7F) {
		eprintf("\ninit error: status=0x%x\n", i);
		for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
			eprintf("%x ", cp[i]);
		eprintf("\n");
		++errors;
	}
}

vret(vec)
int	vec;
{
	eprintf("bad int vec=0x%x\n", vec);
}

wfill(spot)
register unsigned char *spot;
{
	register unsigned int count;

	for (count = 0; count < 512; ++count)
		*spot++ = pattern[(seedy+count)&511];
	++seedy;
}

wcheck(spot, bn)
register unsigned char *spot;
long bn;
{
	register int count;
	register int err = 0;
	register int loopc;

	for (count = 0; count < 512; ++count)
		if (*spot++ != pattern[(seedy+count)&511]) {
			out(0x700, 1);
			eprintf("data err %x != %x ofs=%u b=%u\n",
				*--spot, pattern[(seedy+count)&511],
				count, (int)bn);
			eprintf("disk: ");
			for (loopc = -5; loopc <= 5; ++loopc)
				eprintf("%x ", spot[loopc]);
			eprintf("\nreal: ");
			for (loopc = count-5; loopc <= count+5; ++loopc)
				eprintf("%x ", pattern[(seedy+loopc)&511]);
			eprintf("\n");
			++err;
			break;
		}
	seedy++;
	if (err)
		out(0x700, 1);
	return (err);
}

eprintf(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
{
	if (errsup)
		return;
	printf(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
}