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