/* * check program for djdma for CP/M 68k * * It as assumed that the DJDMA's channel address is at the default. * * For use with CP/M or unix. * * For convenience, we're going to assume * 1K sectors */ #define BUFSIZE 512 #define YES 1 #define NO 0 #define lobyte(a) ((long) (a) >> 0) #define midbyte(a) ((long) (a) >> 8) #define hibyte(a) ((long) (a) >> 16) /* * Timing delay constant. */ #define TIME 150000 #define TIMEOUT NOSTAT #define READIT 0 #define READONLY (0x40) #define NEWLINE '\n' /* * DJDMA I/O space address */ #define DJSTATE 0xff00ef #define RUN 0 /* * Returned status. */ #define OKSTAT (0x40) #define EXEC 0xa2 /* DJDMA execute controller routine */ #define HALT 0x25 /* DJDMA halt command */ #define NOSTAT 0 #define NOSTATUS 0 #define CHANNEL 0x50 /* DJDMA default channel address */ /* * DJDMA op-codes */ #define SETLOGICAL 0x2E #define READTRACK 0x29 /* DJDMA read track command code */ #define SETDMA 0x23 /* DJDMA set DMA address command code */ #define DJSTAT 0x22 /* sense drive status */ #define BRANCH 0x26 #define WPROCT 0x40 #define SWRITE 0x21 /* Sector write */ /* * Return status from commands */ #define OK 0x40 /* * Byte per sector codes from the status command. */ #define S128 0 #define S256 1 #define S512 2 #define S1024 3 /* * Diskette dimensions. */ #define MAXSPT 26 /* * Characteristic bits. */ #define HARD (1 << 1) #define FIVE (1 << 2) #define NOTREADY (1 << 5) /* * Status bits. */ #define DUAL (1 << 2) /* Dual sided media & drive */ struct status { char s_comm, /* command */ s_drive, /* drive number */ s_char, /* drive characteristic byte */ s_secsize, /* sector size byte */ s_status, /* status port byte */ s_complete; /* Complettion status */ }; char *djstate = DJSTATE; /* * struct of the format routine header */ int bpt, /* bytes per track */ drive, /* #of drive being formatted */ inches, nerror, spt, /* Number of sectors per track */ sides = 1, /* Number of sides */ tracks, bps = 1024; /* bytes per sector */ /* * run a djdma status command * * d is the drive select 0-7 */ struct status * djstat () { char *p; p = CHANNEL; *p++ = DJSTAT; *p++ = drive; *p++ = NOSTAT; *p++ = NOSTAT; *p++ = NOSTAT; *p++ = NOSTAT; *p++ = HALT; *p = NOSTAT; djrun (p); if (*p != OKSTAT) { djerror (*p); exit (); } return CHANNEL; } #define SIDE0 0 #define SIDE1 0x80 setaddr (a) char *a; { char *p; p = CHANNEL; *p++ = SETDMA; *p++ = lobyte(a); *p++ = midbyte(a); *p++ = hibyte(a); *p++ = HALT; *p = NOSTAT; djrun (p); } /* * read a track * a is the track no. * b is the side * c is the drive no. * d is the sector table address * e is the data address */ readtrack (a, b, c, d, e) int a, b, c; char *d; char *e; { char *p, *s; setaddr (e); p = CHANNEL; *p++ = READTRACK; *p++ = a; *p++ = b ? SIDE1 : SIDE0; *p++ = c; *p++ = lobyte(d); *p++ = midbyte(d); *p++ = hibyte(d); s = p; *p++ = NOSTAT; *p++ = HALT; *p = NOSTAT; djrun (p); if (*s != OKSTAT) printf ("Cylinder %d, Head %d: ", a, b); djerror (*s); return *s == OKSTAT; } /* * verify a track */ tver (t, s) int t, s; { static char secstat [MAXSPT]; char tbuf [8192]; /* track buffer */ int i; int tocheck; if (inches == 8 && t == 0 && s == 0) { tocheck = 26; } else { tocheck = spt; } fill (secstat, 26, READIT); if (!readtrack (t, s, drive, secstat, tbuf)) return NO; for (i = 0; i < tocheck; i++) { if (secstat[i] != OKSTAT) { printf ("cylinder %d, head %d, ", t, s); djerror (secstat[i]); printf ("\n"); return NO; } } return YES; } /* * djrun - start the disk controller, then wait * a reasonable length of time for the given main memory * location to change. */ djrun (a) char *a; { long i; *a = NOSTAT; *djstate = RUN; /* set the DJDMA into running state */ for (i = TIME; i; i--) /* poll status */ if (*a != NOSTAT) return *a == OKSTAT; return NO; /* timeout */ } /* swrite (d, c, s, a) char *a; { char *p, *st; setaddr (a); p = CHANNEL; *p++ = SWRITE; *p++ = c; /* cylinder * *p++ = s; /* sector * *p++ = d; /* drive * st = p; *p++ = NOSTAT; /* return status * *p++ = HALT; *p = NOSTAT; djrun (p); djerror (*st); return *st == OKSTAT; } */ /* * Display a DJDMA error message for the given status. */ djerror (a) { a &= 0377; if (a == OKSTAT) return; nerror++; switch (a) { case OKSTAT: { break; } case TIMEOUT: { put ("Controller does not respond"); break; } case 0x80: { put ("Improper command code"); break; } case 0x81: { put ("Improper disk drive value"); break; } case 0x82: { put ("Disk drive not ready"); break; } case 0x83: { put ("Improper track value"); break; } case 0x84: { put ("Unreadable medium"); break; } case 0x85: { put ("Improper sector header - No sync byte(s)"); break; } case 0x86: { put ("CRC error in sector header scan"); break; } case 0x87: { put ("Seek error"); break; } case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: { put ("Compare error in sector header scan"); break; } case 0x8E: { put ("CRC error in data field"); break; } case 0x8F: { put ("Improper sector value"); break; } case 0x90: { put ("Media write protected"); break; } case 0x91: { put ("Lost data - DMA channel did not respond"); break; } case 0x92: { put ("Lost command - channel did not respond"); break; } case 0x93: { put ("Timeout waiting for data ID mark"); break; } case 0x94: { put ("Heads failed to move to the home position"); break; } default: { printf ("Unknown error, returned code was %x", a); break; } } put ("\n"); } put (a) char *a; { printf ("%s", a); } main () { int t, s; getdev(); djinit (); nerror = 0; for (t = 0; t < tracks; t++) for (s = 0; s < sides; s++) tver (t, s); if (nerror == 0) printf ("No errors.\n"); else if (nerror == 1) printf ("1 error.\n"); else printf ("%d errors.\n", nerror); } fill (a, b, c) char *a; int b; char c; { while (b--) *a++ = c; } getdev () { char buf [BUFSIZE]; prs ("Morrow's DJDMA checker.\n"); prs ("We expect 1024 byte per sector format\n"); prs ("for 8 or 5 inch diskettes.\n"); prs ("The DJDMA's track read facility is used.\n"); prs ("Device numbers 0-3 correspond to 8 in. drives.\n"); prs ("Numbers 4-7 correspond to 5 1/4 in. drives.\n"); prs ("Specify device number (0 - 7): "); gets (buf); drive = atoi (buf); } djinit () { struct status *s; s = djstat (); if (s->s_char & FIVE) { prs ("5 1/4 inch\n"); tracks = 40; spt = 5; inches = 5; getsides (); } else { printf ("8 inch\n"); tracks = 77; spt = 8; inches = 8; } if (s->s_status & DUAL) sides = 2; if (sides == 2) prs ("Dual sided.\n"); else prs ("Single sided\n"); if (s->s_char & HARD) { tracks = 35; spt = 10; prs ("Hard sectored.\n"); } else { prs ("Soft sectored.\n"); } if (s->s_complete != OKSTAT) { printf ("Drive not ready\n"); exit (); } } getsides () { char buf [BUFSIZE]; printf ("Dual sided? (Y/N) "); gets (buf); if (*buf == 'y' || *buf == 'Y') sides = 2; } prs (a) char *a; { printf ("%s", a); }