/* * RL disk driver * * RL driver modified for the standalone shell. * Armando P. Stettner Digital Equipment Corp. July, 1980 */ #include #include #include "../saio.h" #define BLKRL1 10240 /* Number of UNIX blocks for an RL01 drive */ #define BLKRL2 20480 /* Number of UNIX blocks for an RL02 drive */ #define RLCYLSZ 10240 /* bytes per cylinder */ #define RLSECSZ 256 /* bytes per sector */ #define RESET 013 #define RL02TYP 0200 /* drive type bit */ #define STAT 03 #define GETSTAT 04 #define WCOM 012 #define RCOM 014 #define SEEK 06 #define SEEKHI 5 #define SEEKLO 1 #define RDHDR 010 #define IENABLE 0100 #define CRDY 0200 #define OPI 02000 #define CRCERR 04000 #define TIMOUT 010000 #define NXM 020000 #define DE 040000 struct device { int rlcs , rlba , rlda , rlmp ; } ; #define RLADDR ((struct device *)0174400) #define RL_CNT 1 struct { int cn[4] ; /* location of heads for each drive */ int type[4] ; /* parameter dependent upon drive type (RL01/02) */ int com ; /* read or write command word */ int chn ; /* cylinder and head number */ unsigned int bleft ; /* bytes left to be transferred */ unsigned int bpart ; /* number of bytes transferred */ int sn ; /* sector number */ union { int w[2] ; long l ; } addr ; /* address of memory for transfer */ } rl = {-1,-1,-1,-1, -1,-1,-1,-1} ; /* initialize cn[] and type[] */ rlstrategy(io, func) register struct iob *io ; int func ; { int nblocks ; /* number of UNIX blocks for the drive in question */ int drive ; int dif ; int head ; int ctr ; /* * We must determine what type of drive we are talking to in order * to determine how many blocks are on the device. The rl.type[] * array has been initialized with -1's so that we may test first * contact with a particular drive and do this determination only once. * Sorry tjk for this hack. * * RL02 GET STATUS BAND-AID - Fred Canter 10/14/80 * * For some unknown reason the RL02 (seems to be * only drive 1) does not return a valid drive status * the first time that a GET STATUS request is issued * for the drive, in fact it can take up to three or more * GET STATUS requests to obtain the correct status. * In order to overcome this "HACK" the driver has been * modified to issue a GET STATUS request, validate the * drive status returned, and then use it to determine the * drive type. If a valid status is not returned after eight * attempts, then an error message is printed. */ drive = io->i_unit ; if (rl.type[drive] < 0) { ctr = 0; do { RLADDR->rlda = RESET ; /* load this register; what a dumb controller */ RLADDR->rlcs = (drive << 8) | GETSTAT ; /* set up csr */ while ((RLADDR->rlcs & CRDY) == 0) /* wait for it */ ; } while (((RLADDR->rlmp & 0177477) != 035) && (++ctr < 8)) ; if (ctr >= 8) printf("\nCan't get status of RL unit %d\n",drive) ; if (RLADDR->rlmp & RL02TYP) rl.type[drive] = BLKRL2 ; /* drive is RL02 */ else rl.type[drive] = BLKRL1 ; /* drive RL01 */ /* * When the device is first touched, find out where the heads are. */ /* find where the heads are */ RLADDR->rlcs = (drive << 8) | RDHDR; while ((RLADDR->rlcs&CRDY) == 0) ; /*rl.cn[drive] = (RLADDR->rlmp&0177700) >> 6;*/ rl.cn[drive] = ((RLADDR->rlmp) >> 6) & 01777; /* fix sign bug */ } nblocks = rl.type[drive] ; /* how many blocks on this drive */ if(io->i_bn >= nblocks) return -1 ; rl.chn = io->i_bn/20; rl.sn = (io->i_bn%20) << 1; rl.bleft = io->i_cc; rl.addr.w[0] = segflag & 3; rl.addr.w[1] = (int)io->i_ma ; rl.com = (drive << 8) ; if (func == READ) rl.com |= RCOM; else rl.com |= WCOM; reading: /* * One has to seek an RL head, relativily. */ dif =(rl.cn[drive] >> 1) - (rl.chn >>1); head = (rl.chn & 1) << 4; if (dif < 0) RLADDR->rlda = (-dif <<7) | SEEKHI | head; else RLADDR->rlda = (dif << 7) | SEEKLO | head; RLADDR->rlcs = (drive << 8) | SEEK; rl.cn[drive] = rl.chn; /* keep current, our notion of where the heads are */ if (rl.bleft < (rl.bpart = RLCYLSZ - (rl.sn * RLSECSZ))) rl.bpart = rl.bleft; while ((RLADDR->rlcs&CRDY) == 0) ; RLADDR->rlda = (rl.chn << 6) | rl.sn; RLADDR->rlba = rl.addr.w[1]; RLADDR->rlmp = -(rl.bpart >> 1); RLADDR->rlcs = rl.com | rl.addr.w[0] << 4; while ((RLADDR->rlcs & CRDY) == 0) /* wait for completion */ ; if (RLADDR->rlcs < 0) /* check error bit */ { if (RLADDR->rlcs & 040000) /* Drive error */ { /* * get status from drive */ RLADDR->rlda = STAT; RLADDR->rlcs = (drive << 8) | GETSTAT; while ((RLADDR->rlcs & CRDY) == 0) /* wait for controller */ ; } printf("Rl disk error: cyl=%d, head=%d, sector=%d, rlcs=%o, rlmp=%o\n", rl.chn>>01, rl.chn&01, rl.sn, RLADDR->rlcs, RLADDR->rlmp) ; return -1 ; } /* * Determine if there is more to read to satisfy this request. * This is to compensate for the lacl of spiraling reads. */ if ((rl.bleft -= rl.bpart) > 0) { rl.addr.l += rl.bpart ; rl.sn = 0 ; rl.chn++ ; goto reading ; /* read some more */ } return io->i_cc ; }