1*10775Ssam /* rl.c 4.1 83/02/08 */ 2*10775Ssam 3*10775Ssam /* 4*10775Ssam * Standalone RL02 disk driver 5*10775Ssam */ 6*10775Ssam #include "../machine/pte.h" 7*10775Ssam 8*10775Ssam #include "../h/param.h" 9*10775Ssam #include "../h/inode.h" 10*10775Ssam #include "../h/fs.h" 11*10775Ssam 12*10775Ssam #include "../vaxuba/rlreg.h" 13*10775Ssam #include "../vaxuba/ubareg.h" 14*10775Ssam 15*10775Ssam #include "saio.h" 16*10775Ssam #include "savax.h" 17*10775Ssam 18*10775Ssam u_short rlstd[] = { 0774400 }; 19*10775Ssam short rl_off[] = { 0, 361, 0, -1, -1, -1, -1, -1 }; 20*10775Ssam 21*10775Ssam /* struct to keep state info about the controller */ 22*10775Ssam struct rl_stat { 23*10775Ssam short rl_dn; /* drive number */ 24*10775Ssam short rl_cylnhd; /* cylinder and head */ 25*10775Ssam u_short rl_bleft; /* bytes left to transfer */ 26*10775Ssam u_short rl_bpart; /* bytes transferred */ 27*10775Ssam } rl_stat[] = { -1, 0, 0, 0}; 28*10775Ssam 29*10775Ssam rlopen(io) 30*10775Ssam register struct iob *io; 31*10775Ssam { 32*10775Ssam register struct rldevice *rladdr = 33*10775Ssam (struct rldevice *)ubamem(io->i_unit, rlstd[0]); 34*10775Ssam register struct rl_stat *st = &rl_stat[0]; 35*10775Ssam register int ctr = 0; 36*10775Ssam 37*10775Ssam if (rl_off[io->i_boff] == -1 || 38*10775Ssam io->i_boff < 0 || io->i_boff > 7) 39*10775Ssam _stop("rl bad unit"); 40*10775Ssam 41*10775Ssam /* 42*10775Ssam * DEC reports that: 43*10775Ssam * For some unknown reason the RL02 (seems to be only drive 1) 44*10775Ssam * does not return a valid drive status the first time that a 45*10775Ssam * GET STATUS request is issued for the drive, in fact it can 46*10775Ssam * take up to three or more GET STATUS requests to obtain the 47*10775Ssam * correct status. 48*10775Ssam * In order to overcome this, the driver has been modified to 49*10775Ssam * issue a GET STATUS request and validate the drive status 50*10775Ssam * returned. If a valid status is not returned after eight 51*10775Ssam * attempts, then an error message is printed. 52*10775Ssam */ 53*10775Ssam do { 54*10775Ssam rladdr->rlda.getstat = RL_RESET; 55*10775Ssam rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/ 56*10775Ssam rlwait(rladdr); 57*10775Ssam } while( (rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8 ); 58*10775Ssam 59*10775Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 60*10775Ssam _stop("rl unit does not respond"); 61*10775Ssam 62*10775Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) /* NO RL01'S */ 63*10775Ssam _stop("rl01 unit not supported"); 64*10775Ssam 65*10775Ssam /* Determine disk posistion */ 66*10775Ssam rladdr->rlcs = (io->i_unit << 8) | RL_RHDR; 67*10775Ssam rlwait(rladdr); 68*10775Ssam 69*10775Ssam /* save disk drive posistion */ 70*10775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 71*10775Ssam st->rl_dn = io->i_unit; 72*10775Ssam 73*10775Ssam /* byte offset for cylinder desired */ 74*10775Ssam io->i_boff = rl_off[io->i_boff] * NRLBPSC * NRLTRKS * NRLSECT; 75*10775Ssam } 76*10775Ssam 77*10775Ssam rlstrategy(io, func) 78*10775Ssam register struct iob *io; 79*10775Ssam { 80*10775Ssam register struct rldevice *rladdr = 81*10775Ssam (struct rldevice *)ubamem(io->i_unit, rlstd[0]); 82*10775Ssam register struct rl_stat *st = &rl_stat[0]; 83*10775Ssam int com; 84*10775Ssam daddr_t bn; 85*10775Ssam short cn, sn, head; 86*10775Ssam int diff, ubinfo, ubaddr, errcnt = 0; 87*10775Ssam 88*10775Ssam retry: 89*10775Ssam ubinfo = ubasetup(io, 1); 90*10775Ssam bn = io->i_bn; /* block number */ 91*10775Ssam cn = bn / 40; /* 40 512 byte blocks per cylinder */ 92*10775Ssam sn = (bn % 20) << 1; 93*10775Ssam head = (bn / 20) & 1; 94*10775Ssam st->rl_bleft = io->i_cc; /* total number of bytes to trans */ 95*10775Ssam ubaddr = ubinfo; 96*10775Ssam 97*10775Ssam stupid_rl: 98*10775Ssam /* find out how many cylinders to seek */ 99*10775Ssam diff = (st->rl_cylnhd >> 1) - cn; 100*10775Ssam if ( diff == 0 && (st->rl_cylnhd & 1) == head ) 101*10775Ssam goto noseek; 102*10775Ssam 103*10775Ssam /* first time or we switched drives */ 104*10775Ssam st->rl_dn = io->i_unit; /* drive number */ 105*10775Ssam 106*10775Ssam if ( diff < 0 ) 107*10775Ssam rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4; 108*10775Ssam else 109*10775Ssam rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4; 110*10775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK; 111*10775Ssam 112*10775Ssam /* reset position of drive */ 113*10775Ssam st->rl_cylnhd = (cn << 1) | head; 114*10775Ssam 115*10775Ssam noseek: 116*10775Ssam /* wait for controller and drive */ 117*10775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 118*10775Ssam continue; 119*10775Ssam 120*10775Ssam /* calculate the max number of bytes we can trans */ 121*10775Ssam st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC); 122*10775Ssam if ( st->rl_bleft < st->rl_bpart ) 123*10775Ssam st->rl_bpart = st->rl_bleft; 124*10775Ssam 125*10775Ssam rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn; 126*10775Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 127*10775Ssam rladdr->rlba = ubaddr; 128*10775Ssam 129*10775Ssam com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE); 130*10775Ssam 131*10775Ssam if (func == READ) 132*10775Ssam com |= RL_READ; 133*10775Ssam else 134*10775Ssam com |= RL_WRITE; 135*10775Ssam rladdr->rlcs = com; 136*10775Ssam 137*10775Ssam /* wait for controller and drive */ 138*10775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 139*10775Ssam continue; 140*10775Ssam 141*10775Ssam if (rladdr->rlcs & RL_ERR) { 142*10775Ssam int status; 143*10775Ssam 144*10775Ssam if ( rladdr->rlcs & RL_DE ) { 145*10775Ssam rladdr->rlda.getstat = RL_GSTAT; 146*10775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT; 147*10775Ssam rlwait(rladdr); 148*10775Ssam status = rladdr->rlmp.getstat; 149*10775Ssam rladdr->rlda.getstat = RL_RESET; 150*10775Ssam rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT; 151*10775Ssam rlwait(rladdr); 152*10775Ssam } 153*10775Ssam printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n", 154*10775Ssam cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS, 155*10775Ssam status, RLER_BITS); 156*10775Ssam 157*10775Ssam /* Determine disk posistion */ 158*10775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR; 159*10775Ssam rlwait(rladdr); 160*10775Ssam 161*10775Ssam /* save disk drive posistion */ 162*10775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 163*10775Ssam 164*10775Ssam if (errcnt == 10) { 165*10775Ssam printf("rl: unrecovered error\n"); 166*10775Ssam return (-1); 167*10775Ssam } 168*10775Ssam errcnt++; 169*10775Ssam goto retry; 170*10775Ssam } 171*10775Ssam 172*10775Ssam /* do we have to finish off the rest of the transfer? */ 173*10775Ssam if ( (st->rl_bleft -= st->rl_bpart) > 0 ) { 174*10775Ssam /* increment head and/or cylinder */ 175*10775Ssam if ( ++head > 1 ) { 176*10775Ssam cn++; /* want next cyl, head 0 sector 0 */ 177*10775Ssam head = 0; 178*10775Ssam } 179*10775Ssam 180*10775Ssam /* we always want sector to be zero */ 181*10775Ssam sn = 0; 182*10775Ssam 183*10775Ssam /* 184*10775Ssam * standalone code for ubafree does what regular 185*10775Ssam * ubapurge does and we want to purge last transfer 186*10775Ssam */ 187*10775Ssam ubafree(io, ubinfo); 188*10775Ssam 189*10775Ssam ubaddr = ubinfo + io->i_cc - st->rl_bleft; 190*10775Ssam 191*10775Ssam goto stupid_rl; 192*10775Ssam } 193*10775Ssam 194*10775Ssam ubafree(io, ubinfo); 195*10775Ssam 196*10775Ssam if (errcnt) 197*10775Ssam printf("rl: recovered by retry\n"); 198*10775Ssam return (io->i_cc); 199*10775Ssam } 200*10775Ssam 201*10775Ssam rlwait(rladdr) 202*10775Ssam register struct rldevice *rladdr; 203*10775Ssam { 204*10775Ssam 205*10775Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 206*10775Ssam continue; 207*10775Ssam } 208