123238Smckusick /* 229307Smckusick * 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*33408Skarels * @(#)rl.c 7.2 (Berkeley) 01/28/88 723238Smckusick */ 810775Ssam 910775Ssam /* 1010775Ssam * Standalone RL02 disk driver 1110775Ssam */ 1210775Ssam #include "../machine/pte.h" 1310775Ssam 14*33408Skarels #include "param.h" 15*33408Skarels #include "inode.h" 16*33408Skarels #include "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 43*33408Skarels if (badaddr((char *)rladdr, sizeof(short))) { 44*33408Skarels printf("nonexistent device\n"); 45*33408Skarels return (ENXIO); 46*33408Skarels } 47*33408Skarels if ((unsigned)io->i_boff > 7 || rl_off[io->i_boff] == -1) { 48*33408Skarels printf("rl bad unit\n"); 49*33408Skarels return (EUNIT); 50*33408Skarels } 5110775Ssam 5210775Ssam /* 5310775Ssam * DEC reports that: 5410775Ssam * For some unknown reason the RL02 (seems to be only drive 1) 5510775Ssam * does not return a valid drive status the first time that a 5610775Ssam * GET STATUS request is issued for the drive, in fact it can 5710775Ssam * take up to three or more GET STATUS requests to obtain the 5810775Ssam * correct status. 5910775Ssam * In order to overcome this, the driver has been modified to 6010775Ssam * issue a GET STATUS request and validate the drive status 6110775Ssam * returned. If a valid status is not returned after eight 6210775Ssam * attempts, then an error message is printed. 6310775Ssam */ 6410775Ssam do { 6510775Ssam rladdr->rlda.getstat = RL_RESET; 6610775Ssam rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/ 6710775Ssam rlwait(rladdr); 68*33408Skarels } while ((rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8); 6910775Ssam 70*33408Skarels if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) { 71*33408Skarels printf("rl unit does not respond\n"); 72*33408Skarels return (EUNIT); 73*33408Skarels } 7410775Ssam 75*33408Skarels if ((rladdr->rlmp.getstat & RLMP_DT) == 0) { /* NO RL01'S */ 76*33408Skarels printf("rl01 unit not supported\n"); 77*33408Skarels return (EUNIT); 78*33408Skarels } 7910775Ssam 8010775Ssam /* Determine disk posistion */ 8110775Ssam rladdr->rlcs = (io->i_unit << 8) | RL_RHDR; 8210775Ssam rlwait(rladdr); 8310775Ssam 8410775Ssam /* save disk drive posistion */ 8510775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 8610775Ssam st->rl_dn = io->i_unit; 8710775Ssam 8810775Ssam /* byte offset for cylinder desired */ 8910775Ssam io->i_boff = rl_off[io->i_boff] * NRLBPSC * NRLTRKS * NRLSECT; 90*33408Skarels return (0); 9110775Ssam } 9210775Ssam 9310775Ssam rlstrategy(io, func) 9410775Ssam register struct iob *io; 9510775Ssam { 9610775Ssam register struct rldevice *rladdr = 9710775Ssam (struct rldevice *)ubamem(io->i_unit, rlstd[0]); 9810775Ssam register struct rl_stat *st = &rl_stat[0]; 9910775Ssam int com; 10010775Ssam daddr_t bn; 10110775Ssam short cn, sn, head; 10210775Ssam int diff, ubinfo, ubaddr, errcnt = 0; 10310775Ssam 10410775Ssam retry: 10510775Ssam ubinfo = ubasetup(io, 1); 10610775Ssam bn = io->i_bn; /* block number */ 10710775Ssam cn = bn / 40; /* 40 512 byte blocks per cylinder */ 10810775Ssam sn = (bn % 20) << 1; 10910775Ssam head = (bn / 20) & 1; 11010775Ssam st->rl_bleft = io->i_cc; /* total number of bytes to trans */ 11110775Ssam ubaddr = ubinfo; 11210775Ssam 11310775Ssam stupid_rl: 11410775Ssam /* find out how many cylinders to seek */ 11510775Ssam diff = (st->rl_cylnhd >> 1) - cn; 11610775Ssam if ( diff == 0 && (st->rl_cylnhd & 1) == head ) 11710775Ssam goto noseek; 11810775Ssam 11910775Ssam /* first time or we switched drives */ 12010775Ssam st->rl_dn = io->i_unit; /* drive number */ 12110775Ssam 12210775Ssam if ( diff < 0 ) 12310775Ssam rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4; 12410775Ssam else 12510775Ssam rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4; 12610775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK; 12710775Ssam 12810775Ssam /* reset position of drive */ 12910775Ssam st->rl_cylnhd = (cn << 1) | head; 13010775Ssam 13110775Ssam noseek: 13210775Ssam /* wait for controller and drive */ 13310775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 13410775Ssam continue; 13510775Ssam 13610775Ssam /* calculate the max number of bytes we can trans */ 13710775Ssam st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC); 13810775Ssam if ( st->rl_bleft < st->rl_bpart ) 13910775Ssam st->rl_bpart = st->rl_bleft; 14010775Ssam 14110775Ssam rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn; 14210775Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 14310775Ssam rladdr->rlba = ubaddr; 14410775Ssam 14510775Ssam com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE); 14610775Ssam 14710775Ssam if (func == READ) 14810775Ssam com |= RL_READ; 14910775Ssam else 15010775Ssam com |= RL_WRITE; 15110775Ssam rladdr->rlcs = com; 15210775Ssam 15310775Ssam /* wait for controller and drive */ 15410775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 15510775Ssam continue; 15610775Ssam 15710775Ssam if (rladdr->rlcs & RL_ERR) { 15810775Ssam int status; 15910775Ssam 16010775Ssam if ( rladdr->rlcs & RL_DE ) { 16110775Ssam rladdr->rlda.getstat = RL_GSTAT; 16210775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT; 16310775Ssam rlwait(rladdr); 16410775Ssam status = rladdr->rlmp.getstat; 16510775Ssam rladdr->rlda.getstat = RL_RESET; 16610775Ssam rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT; 16710775Ssam rlwait(rladdr); 16810775Ssam } 16910775Ssam printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n", 17010775Ssam cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS, 17110775Ssam status, RLER_BITS); 17210775Ssam 17310775Ssam /* Determine disk posistion */ 17410775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR; 17510775Ssam rlwait(rladdr); 17610775Ssam 17710775Ssam /* save disk drive posistion */ 17810775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 17910775Ssam 18010775Ssam if (errcnt == 10) { 18110775Ssam printf("rl: unrecovered error\n"); 18210775Ssam return (-1); 18310775Ssam } 18410775Ssam errcnt++; 18510775Ssam goto retry; 18610775Ssam } 18710775Ssam 18810775Ssam /* do we have to finish off the rest of the transfer? */ 18910775Ssam if ( (st->rl_bleft -= st->rl_bpart) > 0 ) { 19010775Ssam /* increment head and/or cylinder */ 19110775Ssam if ( ++head > 1 ) { 19210775Ssam cn++; /* want next cyl, head 0 sector 0 */ 19310775Ssam head = 0; 19410775Ssam } 19510775Ssam 19610775Ssam /* we always want sector to be zero */ 19710775Ssam sn = 0; 19810775Ssam 19910775Ssam /* 20010775Ssam * standalone code for ubafree does what regular 20110775Ssam * ubapurge does and we want to purge last transfer 20210775Ssam */ 20310775Ssam ubafree(io, ubinfo); 20410775Ssam 20510775Ssam ubaddr = ubinfo + io->i_cc - st->rl_bleft; 20610775Ssam 20710775Ssam goto stupid_rl; 20810775Ssam } 20910775Ssam 21010775Ssam ubafree(io, ubinfo); 21110775Ssam 21210775Ssam if (errcnt) 21310775Ssam printf("rl: recovered by retry\n"); 21410775Ssam return (io->i_cc); 21510775Ssam } 21610775Ssam 21710775Ssam rlwait(rladdr) 21810775Ssam register struct rldevice *rladdr; 21910775Ssam { 22010775Ssam 22110775Ssam while ((rladdr->rlcs & RL_CRDY) == 0) 22210775Ssam continue; 22310775Ssam } 22411111Ssam 22511111Ssam rlioctl(io, cmd, arg) 22611111Ssam struct iob *io; 22711111Ssam int cmd; 22811111Ssam caddr_t arg; 22911111Ssam { 23011111Ssam 23111111Ssam return (ECMD); 23211111Ssam } 233