123238Smckusick /* 2*29307Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 323238Smckusick * All rights reserved. The Berkeley software License Agreement 423238Smckusick * specifies the terms and conditions for redistribution. 523238Smckusick * 6*29307Smckusick * @(#)rl.c 7.1 (Berkeley) 06/05/86 723238Smckusick */ 810775Ssam 910775Ssam /* 1010775Ssam * Standalone RL02 disk driver 1110775Ssam */ 1210775Ssam #include "../machine/pte.h" 1310775Ssam 1410775Ssam #include "../h/param.h" 1510775Ssam #include "../h/inode.h" 1610775Ssam #include "../h/fs.h" 1710775Ssam 1810775Ssam #include "../vaxuba/rlreg.h" 1910775Ssam #include "../vaxuba/ubareg.h" 2010775Ssam 2110775Ssam #include "saio.h" 2210775Ssam #include "savax.h" 2310775Ssam 2410775Ssam u_short rlstd[] = { 0774400 }; 2510775Ssam short rl_off[] = { 0, 361, 0, -1, -1, -1, -1, -1 }; 2610775Ssam 2710775Ssam /* struct to keep state info about the controller */ 2810775Ssam struct rl_stat { 2910775Ssam short rl_dn; /* drive number */ 3010775Ssam short rl_cylnhd; /* cylinder and head */ 3110775Ssam u_short rl_bleft; /* bytes left to transfer */ 3210775Ssam u_short rl_bpart; /* bytes transferred */ 3310775Ssam } rl_stat[] = { -1, 0, 0, 0}; 3410775Ssam 3510775Ssam rlopen(io) 3610775Ssam register struct iob *io; 3710775Ssam { 3810775Ssam register struct rldevice *rladdr = 3910775Ssam (struct rldevice *)ubamem(io->i_unit, rlstd[0]); 4010775Ssam register struct rl_stat *st = &rl_stat[0]; 4110775Ssam register int ctr = 0; 4210775Ssam 4310775Ssam if (rl_off[io->i_boff] == -1 || 4410775Ssam io->i_boff < 0 || io->i_boff > 7) 4510775Ssam _stop("rl bad unit"); 4610775Ssam 4710775Ssam /* 4810775Ssam * DEC reports that: 4910775Ssam * For some unknown reason the RL02 (seems to be only drive 1) 5010775Ssam * does not return a valid drive status the first time that a 5110775Ssam * GET STATUS request is issued for the drive, in fact it can 5210775Ssam * take up to three or more GET STATUS requests to obtain the 5310775Ssam * correct status. 5410775Ssam * In order to overcome this, the driver has been modified to 5510775Ssam * issue a GET STATUS request and validate the drive status 5610775Ssam * returned. If a valid status is not returned after eight 5710775Ssam * attempts, then an error message is printed. 5810775Ssam */ 5910775Ssam do { 6010775Ssam rladdr->rlda.getstat = RL_RESET; 6110775Ssam rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/ 6210775Ssam rlwait(rladdr); 6310775Ssam } while( (rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8 ); 6410775Ssam 6510775Ssam if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) 6610775Ssam _stop("rl unit does not respond"); 6710775Ssam 6810775Ssam if ((rladdr->rlmp.getstat & RLMP_DT) == 0 ) /* NO RL01'S */ 6910775Ssam _stop("rl01 unit not supported"); 7010775Ssam 7110775Ssam /* Determine disk posistion */ 7210775Ssam rladdr->rlcs = (io->i_unit << 8) | RL_RHDR; 7310775Ssam rlwait(rladdr); 7410775Ssam 7510775Ssam /* save disk drive posistion */ 7610775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 7710775Ssam st->rl_dn = io->i_unit; 7810775Ssam 7910775Ssam /* byte offset for cylinder desired */ 8010775Ssam io->i_boff = rl_off[io->i_boff] * NRLBPSC * NRLTRKS * NRLSECT; 8110775Ssam } 8210775Ssam 8310775Ssam rlstrategy(io, func) 8410775Ssam register struct iob *io; 8510775Ssam { 8610775Ssam register struct rldevice *rladdr = 8710775Ssam (struct rldevice *)ubamem(io->i_unit, rlstd[0]); 8810775Ssam register struct rl_stat *st = &rl_stat[0]; 8910775Ssam int com; 9010775Ssam daddr_t bn; 9110775Ssam short cn, sn, head; 9210775Ssam int diff, ubinfo, ubaddr, errcnt = 0; 9310775Ssam 9410775Ssam retry: 9510775Ssam ubinfo = ubasetup(io, 1); 9610775Ssam bn = io->i_bn; /* block number */ 9710775Ssam cn = bn / 40; /* 40 512 byte blocks per cylinder */ 9810775Ssam sn = (bn % 20) << 1; 9910775Ssam head = (bn / 20) & 1; 10010775Ssam st->rl_bleft = io->i_cc; /* total number of bytes to trans */ 10110775Ssam ubaddr = ubinfo; 10210775Ssam 10310775Ssam stupid_rl: 10410775Ssam /* find out how many cylinders to seek */ 10510775Ssam diff = (st->rl_cylnhd >> 1) - cn; 10610775Ssam if ( diff == 0 && (st->rl_cylnhd & 1) == head ) 10710775Ssam goto noseek; 10810775Ssam 10910775Ssam /* first time or we switched drives */ 11010775Ssam st->rl_dn = io->i_unit; /* drive number */ 11110775Ssam 11210775Ssam if ( diff < 0 ) 11310775Ssam rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4; 11410775Ssam else 11510775Ssam rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4; 11610775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK; 11710775Ssam 11810775Ssam /* reset position of drive */ 11910775Ssam st->rl_cylnhd = (cn << 1) | head; 12010775Ssam 12110775Ssam noseek: 12210775Ssam /* wait for controller and drive */ 12310775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 12410775Ssam continue; 12510775Ssam 12610775Ssam /* calculate the max number of bytes we can trans */ 12710775Ssam st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC); 12810775Ssam if ( st->rl_bleft < st->rl_bpart ) 12910775Ssam st->rl_bpart = st->rl_bleft; 13010775Ssam 13110775Ssam rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn; 13210775Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 13310775Ssam rladdr->rlba = ubaddr; 13410775Ssam 13510775Ssam com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE); 13610775Ssam 13710775Ssam if (func == READ) 13810775Ssam com |= RL_READ; 13910775Ssam else 14010775Ssam com |= RL_WRITE; 14110775Ssam rladdr->rlcs = com; 14210775Ssam 14310775Ssam /* wait for controller and drive */ 14410775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 14510775Ssam continue; 14610775Ssam 14710775Ssam if (rladdr->rlcs & RL_ERR) { 14810775Ssam int status; 14910775Ssam 15010775Ssam if ( rladdr->rlcs & RL_DE ) { 15110775Ssam rladdr->rlda.getstat = RL_GSTAT; 15210775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT; 15310775Ssam rlwait(rladdr); 15410775Ssam status = rladdr->rlmp.getstat; 15510775Ssam rladdr->rlda.getstat = RL_RESET; 15610775Ssam rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT; 15710775Ssam rlwait(rladdr); 15810775Ssam } 15910775Ssam printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n", 16010775Ssam cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS, 16110775Ssam status, RLER_BITS); 16210775Ssam 16310775Ssam /* Determine disk posistion */ 16410775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR; 16510775Ssam rlwait(rladdr); 16610775Ssam 16710775Ssam /* save disk drive posistion */ 16810775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 16910775Ssam 17010775Ssam if (errcnt == 10) { 17110775Ssam printf("rl: unrecovered error\n"); 17210775Ssam return (-1); 17310775Ssam } 17410775Ssam errcnt++; 17510775Ssam goto retry; 17610775Ssam } 17710775Ssam 17810775Ssam /* do we have to finish off the rest of the transfer? */ 17910775Ssam if ( (st->rl_bleft -= st->rl_bpart) > 0 ) { 18010775Ssam /* increment head and/or cylinder */ 18110775Ssam if ( ++head > 1 ) { 18210775Ssam cn++; /* want next cyl, head 0 sector 0 */ 18310775Ssam head = 0; 18410775Ssam } 18510775Ssam 18610775Ssam /* we always want sector to be zero */ 18710775Ssam sn = 0; 18810775Ssam 18910775Ssam /* 19010775Ssam * standalone code for ubafree does what regular 19110775Ssam * ubapurge does and we want to purge last transfer 19210775Ssam */ 19310775Ssam ubafree(io, ubinfo); 19410775Ssam 19510775Ssam ubaddr = ubinfo + io->i_cc - st->rl_bleft; 19610775Ssam 19710775Ssam goto stupid_rl; 19810775Ssam } 19910775Ssam 20010775Ssam ubafree(io, ubinfo); 20110775Ssam 20210775Ssam if (errcnt) 20310775Ssam printf("rl: recovered by retry\n"); 20410775Ssam return (io->i_cc); 20510775Ssam } 20610775Ssam 20710775Ssam rlwait(rladdr) 20810775Ssam register struct rldevice *rladdr; 20910775Ssam { 21010775Ssam 21110775Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 21210775Ssam continue; 21310775Ssam } 21411111Ssam 21511111Ssam rlioctl(io, cmd, arg) 21611111Ssam struct iob *io; 21711111Ssam int cmd; 21811111Ssam caddr_t arg; 21911111Ssam { 22011111Ssam 22111111Ssam return (ECMD); 22211111Ssam } 223