123238Smckusick /*
235052Skarels * Copyright (c) 1982, 1986, 1988 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*49100Sbostic * @(#)rl.c 7.9 (Berkeley) 05/04/91
723238Smckusick */
810775Ssam
910775Ssam /*
1010775Ssam * Standalone RL02 disk driver
1110775Ssam */
1210775Ssam
1345803Sbostic #include "sys/param.h"
1410775Ssam
1545803Sbostic #include "../include/pte.h"
1645803Sbostic #include "../uba/rlreg.h"
1745803Sbostic #include "../uba/ubareg.h"
1810775Ssam
1945803Sbostic #include "stand/saio.h"
2010775Ssam #include "savax.h"
2110775Ssam
2233542Sbostic #define MAXPART 8
2333542Sbostic #define MAXCTLR 1 /* all addresses must be specified */
2433542Sbostic u_short rlstd[MAXCTLR] = { 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 */
3333542Sbostic } rl_stat[MAXCTLR] = { -1, 0, 0, 0 };
3410775Ssam
rlopen(io)3510775Ssam rlopen(io)
3610775Ssam register struct iob *io;
3710775Ssam {
3833542Sbostic register struct rldevice *rladdr;
3933542Sbostic register struct rl_stat *st;
4010775Ssam register int ctr = 0;
4110775Ssam
4235052Skarels if ((u_int)io->i_adapt >= nuba)
4335052Skarels return (EADAPT);
4433542Sbostic if ((u_int)io->i_ctlr >= MAXCTLR)
4533542Sbostic return (ECTLR);
4633542Sbostic rladdr = (struct rldevice *)ubamem(io->i_adapt, rlstd[io->i_ctlr]);
4733549Sbostic if (badaddr((char *)rladdr, sizeof(short)))
4833408Skarels return (ENXIO);
4933542Sbostic if ((u_int)io->i_part >= MAXPART || rl_off[io->i_part] == -1)
5033542Sbostic return (EPART);
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);
6833408Skarels } while ((rladdr->rlmp.getstat&RLMP_STATUS) != RLMP_STATOK && ++ctr<8);
6910775Ssam
7033408Skarels if ((rladdr->rlcs & RL_DE) || (ctr >= 8)) {
7133542Sbostic printf("rl: unit does not respond\n");
7233408Skarels return (EUNIT);
7333408Skarels }
7410775Ssam
7533408Skarels if ((rladdr->rlmp.getstat & RLMP_DT) == 0) { /* NO RL01'S */
7633408Skarels printf("rl01 unit not supported\n");
7733542Sbostic return (ENXIO);
7833408Skarels }
7910775Ssam
8010775Ssam /* Determine disk posistion */
8110775Ssam rladdr->rlcs = (io->i_unit << 8) | RL_RHDR;
8210775Ssam rlwait(rladdr);
8310775Ssam
8410775Ssam /* save disk drive posistion */
8533542Sbostic st = &rl_stat[io->i_ctlr];
8610775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6;
8710775Ssam st->rl_dn = io->i_unit;
8810775Ssam
8910775Ssam /* byte offset for cylinder desired */
9033542Sbostic io->i_boff = rl_off[io->i_part] * NRLBPSC * NRLTRKS * NRLSECT;
9133408Skarels return (0);
9210775Ssam }
9310775Ssam
rlstrategy(io,func)9410775Ssam rlstrategy(io, func)
9510775Ssam register struct iob *io;
9610775Ssam {
9733542Sbostic register struct rldevice *rladdr;
9833542Sbostic register struct rl_stat *st;
9910775Ssam int com;
10010775Ssam daddr_t bn;
10110775Ssam short cn, sn, head;
10234981Sbostic int diff, ubinfo, ubaaddr, errcnt = 0;
10310775Ssam
10433542Sbostic rladdr = (struct rldevice *)ubamem(io->i_adapt, rlstd[io->i_ctlr]);
10533542Sbostic st = &rl_stat[io->i_ctlr];
10610775Ssam retry:
10710775Ssam ubinfo = ubasetup(io, 1);
10810775Ssam bn = io->i_bn; /* block number */
10910775Ssam cn = bn / 40; /* 40 512 byte blocks per cylinder */
11010775Ssam sn = (bn % 20) << 1;
11110775Ssam head = (bn / 20) & 1;
11210775Ssam st->rl_bleft = io->i_cc; /* total number of bytes to trans */
11334981Sbostic ubaaddr = ubinfo;
11410775Ssam
11510775Ssam stupid_rl:
11610775Ssam /* find out how many cylinders to seek */
11710775Ssam diff = (st->rl_cylnhd >> 1) - cn;
11833542Sbostic if (diff == 0 && (st->rl_cylnhd & 1) == head)
11910775Ssam goto noseek;
12010775Ssam
12110775Ssam /* first time or we switched drives */
12210775Ssam st->rl_dn = io->i_unit; /* drive number */
12310775Ssam
12433542Sbostic if (diff < 0)
12510775Ssam rladdr->rlda.seek = -diff<<7 | RLDA_HGH | head << 4;
12610775Ssam else
12710775Ssam rladdr->rlda.seek = diff<<7 | RLDA_LOW | head << 4;
12810775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_SEEK;
12910775Ssam
13010775Ssam /* reset position of drive */
13110775Ssam st->rl_cylnhd = (cn << 1) | head;
13210775Ssam
13310775Ssam noseek:
13410775Ssam /* wait for controller and drive */
13510775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY)
13610775Ssam continue;
13710775Ssam
13810775Ssam /* calculate the max number of bytes we can trans */
13910775Ssam st->rl_bpart = NRLSECT * NRLBPSC - (sn * NRLBPSC);
14033542Sbostic if (st->rl_bleft < st->rl_bpart)
14110775Ssam st->rl_bpart = st->rl_bleft;
14210775Ssam
14310775Ssam rladdr->rlda.rw = (st->rl_cylnhd << 6) | sn;
14410775Ssam rladdr->rlmp.rw = -(st->rl_bpart >> 1);
14534981Sbostic rladdr->rlba = ubaaddr;
14610775Ssam
14734981Sbostic com = (st->rl_dn << 8) | ((ubaaddr>>12)&RL_BAE);
14810775Ssam
149*49100Sbostic if (func == F_READ)
15010775Ssam com |= RL_READ;
15110775Ssam else
15210775Ssam com |= RL_WRITE;
15310775Ssam rladdr->rlcs = com;
15410775Ssam
15510775Ssam /* wait for controller and drive */
15610775Ssam while( (rladdr->rlcs & RL_DCRDY) != RL_DCRDY)
15710775Ssam continue;
15810775Ssam
15910775Ssam if (rladdr->rlcs & RL_ERR) {
16010775Ssam int status;
16110775Ssam
16233542Sbostic if (rladdr->rlcs & RL_DE) {
16310775Ssam rladdr->rlda.getstat = RL_GSTAT;
16410775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_GETSTAT;
16510775Ssam rlwait(rladdr);
16610775Ssam status = rladdr->rlmp.getstat;
16710775Ssam rladdr->rlda.getstat = RL_RESET;
16810775Ssam rladdr->rlcs = (st->rl_dn <<8) | RL_GETSTAT;
16910775Ssam rlwait(rladdr);
17010775Ssam }
17110775Ssam printf("rl error: (cyl,head,sec)=(%d,%d,%d) cs=%b mp=%b\n",
17210775Ssam cn, head, sn, rladdr->rlcs & 0xffff, RLCS_BITS,
17310775Ssam status, RLER_BITS);
17410775Ssam
17510775Ssam /* Determine disk posistion */
17610775Ssam rladdr->rlcs = (st->rl_dn << 8) | RL_RHDR;
17710775Ssam rlwait(rladdr);
17810775Ssam
17910775Ssam /* save disk drive posistion */
18010775Ssam st->rl_cylnhd = (rladdr->rlmp.readhdr & 0177700) >> 6;
18110775Ssam
18233542Sbostic if (errcnt++ == 10) {
18310775Ssam printf("rl: unrecovered error\n");
18410775Ssam return (-1);
18510775Ssam }
18610775Ssam goto retry;
18710775Ssam }
18810775Ssam
18910775Ssam /* do we have to finish off the rest of the transfer? */
19033542Sbostic if ((st->rl_bleft -= st->rl_bpart) > 0) {
19110775Ssam /* increment head and/or cylinder */
19233542Sbostic if (++head > 1) {
19310775Ssam cn++; /* want next cyl, head 0 sector 0 */
19410775Ssam head = 0;
19510775Ssam }
19610775Ssam
19710775Ssam /* we always want sector to be zero */
19810775Ssam sn = 0;
19910775Ssam
20010775Ssam /*
20110775Ssam * standalone code for ubafree does what regular
20210775Ssam * ubapurge does and we want to purge last transfer
20310775Ssam */
20410775Ssam ubafree(io, ubinfo);
20510775Ssam
20634981Sbostic ubaaddr = ubinfo + io->i_cc - st->rl_bleft;
20710775Ssam
20810775Ssam goto stupid_rl;
20910775Ssam }
21010775Ssam
21110775Ssam ubafree(io, ubinfo);
21210775Ssam
21310775Ssam if (errcnt)
21410775Ssam printf("rl: recovered by retry\n");
21510775Ssam return (io->i_cc);
21610775Ssam }
21710775Ssam
21833542Sbostic static
rlwait(rladdr)21910775Ssam rlwait(rladdr)
22010775Ssam register struct rldevice *rladdr;
22110775Ssam {
22233542Sbostic while ((rladdr->rlcs & RL_CRDY) == 0);
22310775Ssam }
224