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*33542Sbostic * @(#)rl.c 7.3 (Berkeley) 02/23/88 723238Smckusick */ 810775Ssam 910775Ssam /* 1010775Ssam * Standalone RL02 disk driver 1110775Ssam */ 1210775Ssam #include "../machine/pte.h" 1310775Ssam 1433408Skarels #include "param.h" 1533408Skarels #include "inode.h" 1633408Skarels #include "fs.h" 1710775Ssam 1810775Ssam #include "../vaxuba/rlreg.h" 1910775Ssam #include "../vaxuba/ubareg.h" 2010775Ssam 2110775Ssam #include "saio.h" 2210775Ssam #include "savax.h" 2310775Ssam 24*33542Sbostic #define MAXPART 8 25*33542Sbostic #define MAXCTLR 1 /* all addresses must be specified */ 26*33542Sbostic u_short rlstd[MAXCTLR] = { 0774400 }; 2710775Ssam short rl_off[] = { 0, 361, 0, -1, -1, -1, -1, -1 }; 2810775Ssam 2910775Ssam /* struct to keep state info about the controller */ 3010775Ssam struct rl_stat { 3110775Ssam short rl_dn; /* drive number */ 3210775Ssam short rl_cylnhd; /* cylinder and head */ 3310775Ssam u_short rl_bleft; /* bytes left to transfer */ 3410775Ssam u_short rl_bpart; /* bytes transferred */ 35*33542Sbostic } rl_stat[MAXCTLR] = { -1, 0, 0, 0 }; 3610775Ssam 3710775Ssam rlopen(io) 3810775Ssam register struct iob *io; 3910775Ssam { 40*33542Sbostic register struct rldevice *rladdr; 41*33542Sbostic register struct rl_stat *st; 4210775Ssam register int ctr = 0; 4310775Ssam 44*33542Sbostic if ((u_int)io->i_ctlr >= MAXCTLR) 45*33542Sbostic return (ECTLR); 46*33542Sbostic rladdr = (struct rldevice *)ubamem(io->i_adapt, rlstd[io->i_ctlr]); 4733408Skarels if (badaddr((char *)rladdr, sizeof(short))) { 48*33542Sbostic printf("rl: nonexistent device\n"); 4933408Skarels return (ENXIO); 5033408Skarels } 51*33542Sbostic if ((u_int)io->i_part >= MAXPART || rl_off[io->i_part] == -1) 52*33542Sbostic return (EPART); 5310775Ssam 5410775Ssam /* 5510775Ssam * DEC reports that: 5610775Ssam * For some unknown reason the RL02 (seems to be only drive 1) 5710775Ssam * does not return a valid drive status the first time that a 5810775Ssam * GET STATUS request is issued for the drive, in fact it can 5910775Ssam * take up to three or more GET STATUS requests to obtain the 6010775Ssam * correct status. 6110775Ssam * In order to overcome this, the driver has been modified to 6210775Ssam * issue a GET STATUS request and validate the drive status 6310775Ssam * returned. If a valid status is not returned after eight 6410775Ssam * attempts, then an error message is printed. 6510775Ssam */ 6610775Ssam do { 6710775Ssam rladdr->rlda.getstat = RL_RESET; 6810775Ssam rladdr->rlcs = (io->i_unit <<8) | RL_GETSTAT; /* Get status*/ 6910775Ssam rlwait(rladdr); 7033408Skarels } while ((rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8); 7110775Ssam 7233408Skarels if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) { 73*33542Sbostic printf("rl: unit does not respond\n"); 7433408Skarels return (EUNIT); 7533408Skarels } 7610775Ssam 7733408Skarels if ((rladdr->rlmp.getstat & RLMP_DT) == 0) { /* NO RL01'S */ 7833408Skarels printf("rl01 unit not supported\n"); 79*33542Sbostic return (ENXIO); 8033408Skarels } 8110775Ssam 8210775Ssam /* Determine disk posistion */ 8310775Ssam rladdr->rlcs = (io->i_unit << 8) | RL_RHDR; 8410775Ssam rlwait(rladdr); 8510775Ssam 8610775Ssam /* save disk drive posistion */ 87*33542Sbostic st = &rl_stat[io->i_ctlr]; 8810775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 8910775Ssam st->rl_dn = io->i_unit; 9010775Ssam 9110775Ssam /* byte offset for cylinder desired */ 92*33542Sbostic io->i_boff = rl_off[io->i_part] * NRLBPSC * NRLTRKS * NRLSECT; 9333408Skarels return (0); 9410775Ssam } 9510775Ssam 9610775Ssam rlstrategy(io, func) 9710775Ssam register struct iob *io; 9810775Ssam { 99*33542Sbostic register struct rldevice *rladdr; 100*33542Sbostic register struct rl_stat *st; 10110775Ssam int com; 10210775Ssam daddr_t bn; 10310775Ssam short cn, sn, head; 10410775Ssam int diff, ubinfo, ubaddr, errcnt = 0; 10510775Ssam 106*33542Sbostic rladdr = (struct rldevice *)ubamem(io->i_adapt, rlstd[io->i_ctlr]); 107*33542Sbostic st = &rl_stat[io->i_ctlr]; 10810775Ssam retry: 10910775Ssam ubinfo = ubasetup(io, 1); 11010775Ssam bn = io->i_bn; /* block number */ 11110775Ssam cn = bn / 40; /* 40 512 byte blocks per cylinder */ 11210775Ssam sn = (bn % 20) << 1; 11310775Ssam head = (bn / 20) & 1; 11410775Ssam st->rl_bleft = io->i_cc; /* total number of bytes to trans */ 11510775Ssam ubaddr = ubinfo; 11610775Ssam 11710775Ssam stupid_rl: 11810775Ssam /* find out how many cylinders to seek */ 11910775Ssam diff = (st->rl_cylnhd >> 1) - cn; 120*33542Sbostic if (diff == 0 && (st->rl_cylnhd & 1) == head) 12110775Ssam goto noseek; 12210775Ssam 12310775Ssam /* first time or we switched drives */ 12410775Ssam st->rl_dn = io->i_unit; /* drive number */ 12510775Ssam 126*33542Sbostic if (diff < 0) 12710775Ssam rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4; 12810775Ssam else 12910775Ssam rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4; 13010775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK; 13110775Ssam 13210775Ssam /* reset position of drive */ 13310775Ssam st->rl_cylnhd = (cn << 1) | head; 13410775Ssam 13510775Ssam noseek: 13610775Ssam /* wait for controller and drive */ 13710775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 13810775Ssam continue; 13910775Ssam 14010775Ssam /* calculate the max number of bytes we can trans */ 14110775Ssam st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC); 142*33542Sbostic if (st->rl_bleft < st->rl_bpart) 14310775Ssam st->rl_bpart = st->rl_bleft; 14410775Ssam 14510775Ssam rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn; 14610775Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1); 14710775Ssam rladdr->rlba = ubaddr; 14810775Ssam 14910775Ssam com = (st->rl_dn << 8) | ((ubaddr>>12)&RL_BAE); 15010775Ssam 15110775Ssam if (func == READ) 15210775Ssam com |= RL_READ; 15310775Ssam else 15410775Ssam com |= RL_WRITE; 15510775Ssam rladdr->rlcs = com; 15610775Ssam 15710775Ssam /* wait for controller and drive */ 15810775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY) 15910775Ssam continue; 16010775Ssam 16110775Ssam if (rladdr->rlcs & RL_ERR) { 16210775Ssam int status; 16310775Ssam 164*33542Sbostic if (rladdr->rlcs & RL_DE) { 16510775Ssam rladdr->rlda.getstat = RL_GSTAT; 16610775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT; 16710775Ssam rlwait(rladdr); 16810775Ssam status = rladdr->rlmp.getstat; 16910775Ssam rladdr->rlda.getstat = RL_RESET; 17010775Ssam rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT; 17110775Ssam rlwait(rladdr); 17210775Ssam } 17310775Ssam printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n", 17410775Ssam cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS, 17510775Ssam status, RLER_BITS); 17610775Ssam 17710775Ssam /* Determine disk posistion */ 17810775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR; 17910775Ssam rlwait(rladdr); 18010775Ssam 18110775Ssam /* save disk drive posistion */ 18210775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6; 18310775Ssam 184*33542Sbostic if (errcnt++ == 10) { 18510775Ssam printf("rl: unrecovered error\n"); 18610775Ssam return (-1); 18710775Ssam } 18810775Ssam goto retry; 18910775Ssam } 19010775Ssam 19110775Ssam /* do we have to finish off the rest of the transfer? */ 192*33542Sbostic if ((st->rl_bleft -= st->rl_bpart) > 0) { 19310775Ssam /* increment head and/or cylinder */ 194*33542Sbostic if (++head > 1) { 19510775Ssam cn++; /* want next cyl, head 0 sector 0 */ 19610775Ssam head = 0; 19710775Ssam } 19810775Ssam 19910775Ssam /* we always want sector to be zero */ 20010775Ssam sn = 0; 20110775Ssam 20210775Ssam /* 20310775Ssam * standalone code for ubafree does what regular 20410775Ssam * ubapurge does and we want to purge last transfer 20510775Ssam */ 20610775Ssam ubafree(io, ubinfo); 20710775Ssam 20810775Ssam ubaddr = ubinfo + io->i_cc - st->rl_bleft; 20910775Ssam 21010775Ssam goto stupid_rl; 21110775Ssam } 21210775Ssam 21310775Ssam ubafree(io, ubinfo); 21410775Ssam 21510775Ssam if (errcnt) 21610775Ssam printf("rl: recovered by retry\n"); 21710775Ssam return (io->i_cc); 21810775Ssam } 21910775Ssam 220*33542Sbostic static 22110775Ssam rlwait(rladdr) 22210775Ssam register struct rldevice *rladdr; 22310775Ssam { 224*33542Sbostic while ((rladdr->rlcs & RL_CRDY) == 0); 22510775Ssam } 226