|
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 - download
Length: 12691 (0x3193) Types: TextFile Notes: UNIX file Names: »tcfatasi.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦2d53db1df⟧ UNIX Filesystem └─ ⟦this⟧ »frankh/format/tcfatasi.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 * July 4, 1985 (fah) put in Hitachi DK511-5 parameters */ #define CMDBLKPADDR (0x80000L) /* WD command blk phys addr */ #define BUFPADDR (0x80400L) /* CMDBLKPADDR + 1K */ #define LONGBUFPADDR (0xA0000L) /* CMDBLKPADDR + 128K */ #define VERS "V4.3" /* 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 wdload(); int wduload(); int wdopen(); int wdread(); int wdwrite(); int wdblock(); 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 */ 9, /* Major index */ wdopen, /* Open */ nulldev, /* Close */ wdblock, /* Block */ wdread, /* Read */ wdwrite, /* Write */ nonedev, /* Ioctl */ nulldev, /* Powerfail */ nulldev, /* Timeout */ wdload, /* Load */ wduload /* 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, "Seagate ST-212 4 head 10MB half-height", 4, 306 }, { SIXTEENuS, (4<<4)|(612/256), 612%256, 128/16, 128/16, NSEC, "MiniScribe 4 head 20MB half-height", 4, 612 }, { SIXTEENuS, (4<<4)|(20/256), 20%256, 20/16, 20/16, NSEC, "4 head 20 cylinder test disk", 4, 20 }, { SIXTEENuS, (7<<4)|(704/256), 704%256, 352/16, 352/16, NSEC, "Atasi 7 head 42MB full-height", 7, 704 }, { SIXTEENuS, (7<<4)|(698/256), 698%256, 348/16, 348/16, NSEC, "Hitachi DK511-5 40mb", 7, 698 } }; 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... */ wdload() { register int trk, cyl; register long l; register unsigned pass = 0; register int ans, i; register int tfmt, tver, bwrite, bread, rndread; register int prwrite, prread, cylread, cylrdwr; /* sphi(); never to be set low again! */ timeouts = 0; errors=0; unit=1; typeno=4; 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); printf("Drive types:\n"); for (i = 0; i < (sizeof(wdinfo)/sizeof(wdinfo[0])); ++i) printf("%d) %s\n", i, wdinfo[i].p_devname); typeno = 3; 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 = 1; patno = 1; printf("Disk parameters: unit=%d sectors=%d heads=%d cylinders=%d\n", unit, nsec, ntrk, ncyl); printf("\nFORMATTING unit 1!!\n"); ++tfmt; ++tver; 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; } 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); } printf("\n\007Unit %d: pass count = %d, timeouts = %d errors=%d\n", unit, ++pass, timeouts, errors); typeno = 4; 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; ++errors; #ifndef NOINTERRUPTS out(WDIO, 0); #endif } #ifdef NOINTERRUPTS out(WDIO, 0); /* reset IEO on DMA chip */ #endif } 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"); ++errors; } } 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]); ++errors; } } wderr(cp) char *cp; { eprintf("\n%s", cp); while (1) ; } wdintr(id) int id; { #ifdef NOINTERRUPTS eprintf("wdintr: got a spurious interrupt !!!\n"); ++errors; #else wdiflag++; out(WDIO, 0); /* reset IEO on DMA chip */ #endif } wdopen() { eprintf("wdopen: \n"); } wduload() { } /* * 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); }