|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 12602 (0x313a)
Types: TextFile
Notes: UNIX file
Names: »tatasi.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦2d53db1df⟧ UNIX Filesystem
└─⟦this⟧ »frankh/format/tatasi.c«
/* (-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.2a" /* 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
int errors;
int timeouts;
unsigned pass;
int badblk;
int badblkv;
int ftload();
int ftuload();
int ftopen();
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 */
nulldev, /* Read */
nulldev, /* 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 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 int trk, cyl;
register long l;
register int ans, i;
register int tfmt, tver, bwrite, bread, rndread;
register int prwrite, prread, cylread, cylrdwr;
pass=0; badblk=0; /* set these only once! */
unit=0; typeno=3; 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 = 3;
printf("\nDrive 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);
++tfmt;
++tver;
#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:
if (tfmt) {
printf("Starting disk format\n");
for (cyl = 0; cyl < ncyl; ++cyl)
for (trk = 0; trk < ntrk; ++trk)
wdfmttrk(trk, cyl);
}
if (tver) {
printf("Starting verify phase:\n");
for (cyl = 0; cyl < ncyl; ++cyl)
for (trk = 0; trk < ntrk; ++trk)
wdvfytrk(trk, cyl);
}
if (badblk < badblkv)
badblk = badblkv;
printf("\n\007Unit %d: pass count = %d, timeouts = %d bad blocks=%d\n",
unit, ++pass, timeouts, badblk);
typeno = 3;
wdsetparam();
}
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, (paddr_t)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;
#ifndef NOINTERRUPTS
out(WDIO, 0);
#endif
}
#ifdef NOINTERRUPTS
out(WDIO, 0); /* reset IEO on DMA chip */
#endif
}
ftuload()
{
}
wdfmttrk(t, c)
{
register int i;
register WDCMD *cbp;
register char *bp;
register unsigned char *cp;
register int count;
register long offs;
eprintf("t=%d c=%d\r", t, c);
offs = (nsec * (long)t) + (nblkcyl * (long)c);
bp = pfix(WDS, (paddr_t)BUFPADDR);
if (t < 0 || t >= ntrk)
wderr("track # out of bounds\n");
i = (nsec - t) % nsec;
for (count = 0; count < nsec; ++count) {
*bp++ = 0;
*bp++ = i;
i = (i + 1) % nsec;
}
cbp = (WDCMD *) pfix(WDS, (paddr_t)CMDBLKPADDR);
for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
cp[i] = 0;
cbp->c_opcode = WDFMTT; /* format track */
cbp->c_blockcnt = nsec;
cbp->c_highdma =(BUFPADDR >> 16); /* phys segment */
cbp->c_middma = (BUFPADDR >> 8); /* offset */
cbp->c_lowdma = 0x00;
cbp->c_lunhiaddr = (unit << 5) | (offs >> 16);
cbp->c_midaddr = offs >> 8;
cbp->c_lowaddr = offs;
cbp->c_errorbits = 0xff; /* make ready */
wdwait(); /* wait for i/o complete */
cbp = (WDCMD *) pfix(WDS, (paddr_t)CMDBLKPADDR);
i = cbp->c_errorbits;
if (i & 0x7F) {
eprintf("\nformat error: %x\n", i);
for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
eprintf("%x ", cp[i]);
eprintf("\n");
++badblk; /* Just bad blocks counted now */
}
}
wdvfytrk(t, c)
{
register int i;
register WDCMD *cbp;
register unsigned char *cp;
register long offs;
offs = (nsec * (long)t) + (nblkcyl * (long)c);
eprintf("t=%d c=%d\r", t, c);
if (t < 0 || t >= ntrk)
wderr("track # out of bounds\n");
cbp = (WDCMD *) pfix(WDS, (paddr_t)CMDBLKPADDR);
for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
cp[i] = 0;
cbp->c_opcode = WDCTF; /* check track format */
cbp->c_blockcnt = nsec;
cbp->c_highdma =(BUFPADDR >> 16);
cbp->c_middma = (BUFPADDR >> 8);
cbp->c_lowdma = 0x00;
cbp->c_lunhiaddr = (unit << 5) | (offs >> 16);
cbp->c_midaddr = offs >> 8;
cbp->c_lowaddr = offs;
cbp->c_errorbits = 0xff; /* make ready */
wdwait(); /* wait for i/o complete */
cbp = (WDCMD *) pfix(WDS, (paddr_t)CMDBLKPADDR);
i = cbp->c_errorbits;
if (i & 0x7F) {
eprintf("\nverify error: %x\n", i);
for (cp = cbp, i = 0; i < sizeof(WDCMD); ++i)
eprintf("%x ", cp[i]);
++badblkv; /* second bad block counter */
}
}
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");
}
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, (paddr_t)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, (paddr_t)LONGBUFPADDR);
*ip = wdinfo[typeno];
wdwait(); /* wait for i/o complete */
cbp = (WDCMD *) pfix(WDS, (paddr_t)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);
}