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