Commit | Line | Data |
---|---|---|
7bc8d985 | 1 | int cs1del; |
008c0481 | 2 | int printsw; |
7bc8d985 | 3 | /* %H% 3.2 %G% */ |
008c0481 BJ |
4 | |
5 | /* | |
6 | * Emulex UNIBUS disk driver with overlapped seeks and ECC recovery. | |
7 | * | |
7bc8d985 BJ |
8 | * NB: This device is very sensitive: be aware that the code is the way |
9 | * it is for good reason and that there are delay loops here which may | |
10 | * have to be lengthened if your processor is faster and which should | |
11 | * probably be shortened if your processor is slower. | |
12 | * | |
008c0481 BJ |
13 | * This driver has been tested on a SC-11B Controller, configured |
14 | * with the following internal switch settings: | |
15 | * SW1-1 5/19 surfaces (off, 19 surfaces on Ampex 9300) | |
16 | * SW1-2 chksum enable (off, checksum disabled) | |
17 | * SW1-3 volume select (off, 815 cylinders) | |
18 | * SW1-4 sector select (on, 32 sectors) | |
19 | * SW1-5 unused (off) | |
20 | * SW1-6 port select (on, single port) | |
21 | * SW1-7 npr delay (off, disable) | |
22 | * SW1-8 ecc test mode (off, disable) | |
23 | * and top mounted switches: | |
24 | * SW2-1 extend opcodes (off=open, disable) | |
25 | * SW2-2 extend diag (off=open, disable) | |
26 | * SW2-3 4 wd dma burst (off=open, disable) | |
27 | * SW2-4 unused (off=open) | |
28 | * | |
29 | * The controller transfers data much more rapidly with SW2-3 set, | |
30 | * but we have previously experienced problems with it set this way. | |
31 | * We intend to try this again in the near future. | |
32 | * | |
33 | * wnj June 14, 1980 | |
34 | */ | |
35 | ||
36 | #include "../h/param.h" | |
37 | #include "../h/systm.h" | |
38 | #include "../h/buf.h" | |
39 | #include "../h/conf.h" | |
40 | #include "../h/dir.h" | |
41 | #include "../h/user.h" | |
42 | #include "../h/map.h" | |
43 | #include "../h/mba.h" | |
44 | #include "../h/mtpr.h" | |
45 | #include "../h/pte.h" | |
46 | #include "../h/uba.h" | |
47 | #include "../h/vm.h" | |
48 | ||
49 | /* | |
50 | * Define number of drives, and range of sampling information to be used. | |
51 | * | |
52 | * Normally, DK_N .. DK_N+NUP-1 gather individual drive stats, | |
53 | * and DK_N+NUP gathers controller transferring stats. | |
54 | * | |
55 | * If DK_N+NUP > DK_NMAX, then transfer stats are divided per drive. | |
56 | * If DK_NMAX is yet smaller, some drives are not monitored. | |
57 | */ | |
58 | #define DK_N 1 | |
59 | #define DK_NMAX 2 | |
60 | ||
61 | #define ushort unsigned short | |
62 | ||
63 | struct device | |
64 | { | |
65 | ushort upcs1; /* control and status register 1 */ | |
66 | short upwc; /* word count register */ | |
67 | ushort upba; /* UNIBUS address register */ | |
68 | ushort upda; /* desired address register */ | |
69 | ushort upcs2; /* control and status register 2 */ | |
70 | ushort upds; /* drive Status */ | |
71 | ushort uper1; /* error register 1 */ | |
72 | ushort upas; /* attention summary */ | |
73 | ushort upla; /* look ahead */ | |
74 | ushort updb; /* data buffer */ | |
75 | ushort upmr; /* maintenance */ | |
76 | ushort updt; /* drive type */ | |
77 | ushort upsn; /* serial number */ | |
78 | ushort upof; /* offset register */ | |
79 | ushort updc; /* desired cylinder address register */ | |
80 | ushort upcc; /* current cylinder */ | |
81 | ushort uper2; /* error register 2 */ | |
82 | ushort uper3; /* error register 3 */ | |
83 | ushort upec1; /* burst error bit position */ | |
84 | ushort upec2; /* burst error bit pattern */ | |
85 | }; | |
86 | ||
87 | #define UPADDR ((struct device *)(UBA0_DEV + 0176700)) | |
88 | ||
89 | #define NUP 2 /* Number of drives this installation */ | |
90 | ||
91 | #define NSECT 32 | |
92 | #define NTRAC 19 | |
93 | ||
94 | /* | |
95 | * Constants controlling on-cylinder SEARCH usage. | |
96 | * | |
97 | * We assume that it takes SDIST sectors of time to set up a transfer. | |
98 | * If a drive is on-cylinder, and between SDIST and SDIST+RDIST sectors | |
99 | * from the first sector to be transferred, then we just perform the | |
100 | * transfer. SDIST represents interrupt latency, RDIST the amount | |
101 | * of rotation which is tolerable to avoid another interrupt. | |
102 | */ | |
7bc8d985 BJ |
103 | #define SDIST 3 /* 2-3 sectors 1-1.5 msec */ |
104 | #define RDIST 6 /* 5-6 sectors 2.5-3 msec */ | |
008c0481 BJ |
105 | |
106 | /* | |
107 | * To fill a 300M drive: | |
108 | * A is designed to be used as a root. | |
109 | * B is suitable for a swap area. | |
110 | * H is the primary storage area. | |
111 | * On systems with RP06'es, we normally use only 291346 blocks of the H | |
112 | * area, and use DEF or G to cover the rest of the drive. The C system | |
113 | * covers the whole drive and can be used for pack-pack copying. | |
114 | */ | |
115 | struct size | |
116 | { | |
117 | daddr_t nblocks; | |
118 | int cyloff; | |
119 | } up_sizes[8] = { | |
120 | 15884, 0, /* A=cyl 0 thru 26 */ | |
121 | 33440, 27, /* B=cyl 27 thru 81 */ | |
122 | 494912, 0, /* C=cyl 0 thru 814 */ | |
123 | 15884, 562, /* D=cyl 562 thru 588 */ | |
124 | 55936, 589, /* E=cyl 589 thru 680 */ | |
125 | 81472, 681, /* F=cyl 681 thru 814 */ | |
126 | 153824, 562, /* G=cyl 562 thru 814 */ | |
127 | 445664, 82, /* H=cyl 82 thru 814 */ | |
128 | /* Later, and more safely for H area... | |
129 | 291346, 82, /* H=cyl 82 thru 561 */ | |
130 | }; | |
131 | ||
132 | /* | |
133 | * The following defines are used in offset positioning | |
134 | * when trying to recover disk errors, with the constants being | |
135 | * +/- microinches. Note that header compare inhibit (HCI) is not | |
136 | * tried (this makes sense only during read, in any case.) | |
137 | * | |
138 | * ARE ALL THESE IMPLEMENTED ON 9300? | |
139 | */ | |
140 | #define P400 020 | |
141 | #define M400 0220 | |
142 | #define P800 040 | |
143 | #define M800 0240 | |
144 | #define P1200 060 | |
145 | #define M1200 0260 | |
146 | #define HCI 020000 | |
147 | ||
148 | int up_offset[16] = | |
149 | { | |
150 | P400, M400, P400, M400, | |
151 | P800, M800, P800, M800, | |
152 | P1200, M1200, P1200, M1200, | |
153 | 0, 0, 0, 0, | |
154 | }; | |
155 | ||
156 | /* | |
157 | * Each drive has a table uputab[i]. On this table are sorted the | |
158 | * pending requests implementing an elevator algorithm (see dsort.c.) | |
159 | * In the upustart() routine, each drive is independently advanced | |
160 | * until it is on the desired cylinder for the next transfer and near | |
161 | * the desired sector. The drive is then chained onto the uptab | |
162 | * table, and the transfer is initiated by the upstart() routine. | |
163 | * When the transfer is completed the driver reinvokes the upustart() | |
164 | * routine to set up the next transfer. | |
165 | */ | |
166 | struct buf uptab; | |
167 | struct buf uputab[NUP]; | |
168 | ||
169 | struct buf rupbuf; /* Buffer for raw i/o */ | |
170 | ||
171 | /* Drive commands, placed in upcs1 */ | |
172 | #define GO 01 /* Go bit, set in all commands */ | |
173 | #define PRESET 020 /* Preset drive at init or after errors */ | |
174 | #define OFFSET 014 /* Offset heads to try to recover error */ | |
175 | #define RTC 016 /* Return to center-line after OFFSET */ | |
176 | #define SEARCH 030 /* Search for cylinder+sector */ | |
177 | #define RECAL 06 /* Recalibrate, needed after seek error */ | |
178 | #define DCLR 010 /* Drive clear, after error */ | |
179 | #define WCOM 060 /* Write */ | |
180 | #define RCOM 070 /* Read */ | |
181 | ||
182 | /* Other bits of upcs1 */ | |
183 | #define IE 0100 /* Controller wide interrupt enable */ | |
184 | #define TRE 040000 /* Transfer error */ | |
7bc8d985 | 185 | #define RDY 020 /* Transfer terminated */ |
008c0481 BJ |
186 | |
187 | /* Drive status bits of upds */ | |
188 | #define PIP 020000 /* Positioning in progress */ | |
189 | #define ERR 040000 /* Error has occurred, DCLR necessary */ | |
190 | #define VV 0100 /* Volume is valid, set by PRESET */ | |
191 | #define DPR 0400 /* Drive has been preset */ | |
192 | #define MOL 010000 /* Drive is online, heads loaded, etc */ | |
193 | #define DRY 0200 /* Drive ready */ | |
194 | ||
195 | /* Bits of uper1 */ | |
196 | #define DCK 0100000 /* Ecc error occurred */ | |
197 | #define ECH 0100 /* Ecc error was unrecoverable */ | |
198 | #define WLE 04000 /* Attempt to write read-only drive */ | |
199 | ||
200 | /* Bits of upof; the offset bits above are also in this register */ | |
201 | #define FMT22 010000 /* 16 bits/word, must be always set */ | |
202 | ||
203 | #define b_cylin b_resid | |
204 | ||
205 | int up_ubinfo; /* Information about UBA usage saved here */ | |
206 | /* | |
207 | * The EMULEX controller balks if accessed quickly after | |
208 | * certain operations. The exact timing has not yet been | |
209 | * determined, but delays are known to be needed when changing | |
210 | * the selected drive (by writing in upcs2), and thought to be | |
211 | * needed after operations like PRESET and DCLR. The following | |
212 | * variables control the delay, DELAY(n) is approximately n usec. | |
213 | */ | |
214 | int idelay = 500; /* Delay after PRESET or DCLR */ | |
215 | int sdelay = 500; /* Delay after selecting drive in upcs2 */ | |
7bc8d985 BJ |
216 | int iedel1 = 500; |
217 | int iedel2 = 500; | |
218 | int iedel3 = 0; | |
219 | int iedel4 = 500; | |
008c0481 BJ |
220 | |
221 | #define DELAY(N) { register int d; d = N; while (--d > 0); } | |
222 | ||
223 | int nwaitcs2; /* How many sdelay loops ? */ | |
224 | int neasycs2; /* How many sdelay loops not needed ? */ | |
225 | ||
226 | #ifdef INTRLVE | |
227 | daddr_t dkblock(); | |
228 | #endif | |
229 | ||
230 | /* | |
231 | * Queue an i/o request for a drive, checking first that it is in range. | |
232 | * | |
233 | * A unit start is issued if the drive is inactive, causing | |
234 | * a SEARCH for the correct cylinder/sector. If the drive is | |
235 | * already nearly on the money and the controller is not transferring | |
236 | * we kick it to start the transfer. | |
237 | */ | |
238 | upstrategy(bp) | |
239 | register struct buf *bp; | |
240 | { | |
241 | register struct buf *dp; | |
242 | register unit, xunit; | |
243 | long sz, bn; | |
244 | ||
245 | xunit = minor(bp->b_dev) & 077; | |
246 | sz = bp->b_bcount; | |
247 | sz = (sz+511) >> 9; /* transfer size in 512 byte sectors */ | |
248 | unit = dkunit(bp); | |
249 | if (unit >= NUP || | |
250 | bp->b_blkno < 0 || | |
251 | (bn = dkblock(bp))+sz > up_sizes[xunit&07].nblocks) { | |
252 | bp->b_flags |= B_ERROR; | |
253 | iodone(bp); | |
254 | return; | |
255 | } | |
256 | bp->b_cylin = bn/(NSECT*NTRAC) + up_sizes[xunit&07].cyloff; | |
257 | dp = &uputab[unit]; | |
258 | (void) spl5(); | |
259 | disksort(dp, bp); | |
260 | if (dp->b_active == 0) { | |
261 | upustart(unit); | |
262 | if (uptab.b_actf && uptab.b_active == 0) | |
263 | upstart(); | |
264 | } | |
265 | (void) spl0(); | |
266 | } | |
267 | ||
268 | /* | |
269 | * Start activity on specified drive; called when drive is inactive | |
270 | * and new transfer request arrives and also when upas indicates that | |
271 | * a SEARCH command is complete. | |
272 | */ | |
273 | upustart(unit) | |
274 | register unit; | |
275 | { | |
276 | register struct buf *bp, *dp; | |
277 | register struct device *upaddr = UPADDR; | |
278 | daddr_t bn; | |
279 | int sn, cn, csn; | |
280 | ||
281 | if (printsw&1) printf("upustart\n"); | |
7bc8d985 | 282 | if (unit >= NUP) |
008c0481 | 283 | return; |
7bc8d985 BJ |
284 | /* |
285 | * Whether or not it was before, this unit is no longer busy. | |
286 | * Check to see if there is (still or now) a request in this | |
287 | * drives queue, and if there is, select this unit. | |
288 | */ | |
008c0481 BJ |
289 | if (unit+DK_N <= DK_NMAX) |
290 | dk_busy &= ~(1<<(unit+DK_N)); | |
291 | dp = &uputab[unit]; | |
7bc8d985 | 292 | if ((bp = dp->b_actf) == NULL) |
008c0481 | 293 | return; |
008c0481 BJ |
294 | if ((upaddr->upcs2 & 07) != unit) { |
295 | upaddr->upcs2 = unit; | |
296 | DELAY(sdelay); | |
297 | nwaitcs2++; | |
298 | } else | |
299 | neasycs2++; | |
7bc8d985 BJ |
300 | /* |
301 | * If we have changed packs or just initialized, | |
302 | * the the volume will not be valid; if so, clear | |
303 | * the drive, preset it and put in 16bit/word mode. | |
304 | */ | |
305 | if ((upaddr->upds & VV) == 0) { | |
306 | upaddr->upcs1 = IE|DCLR|GO; | |
307 | DELAY(idelay); | |
008c0481 BJ |
308 | upaddr->upcs1 = IE|PRESET|GO; |
309 | DELAY(idelay); | |
310 | upaddr->upof = FMT22; | |
311 | } | |
312 | /* | |
7bc8d985 BJ |
313 | * We are called from upstrategy when a new request arrives |
314 | * if we are not already active (with dp->b_active == 0), | |
315 | * and we then set dp->b_active to 1 if we are to SEARCH | |
316 | * for the desired cylinder, or 2 if we are on-cylinder. | |
317 | * If we SEARCH then we will later be called from upintr() | |
318 | * when the search is complete, and will link this disk onto | |
319 | * the uptab. We then set dp->b_active to 2 so that upintr() | |
320 | * will not call us again. | |
321 | * | |
322 | * NB: Other drives clear the bit in the attention status | |
323 | * (i.e. upas) register corresponding to the drive when they | |
324 | * place the drive on the ready (i.e. uptab) queue. This does | |
325 | * not work with the Emulex, as the controller hangs the UBA | |
326 | * of the VAX shortly after the upas register is set, for | |
327 | * reasons unknown. This only occurs in multi-spindle configurations, | |
328 | * but to avoid the problem we use the fact that dp->b_active is | |
329 | * 2 to replace the clearing of the upas bit. | |
008c0481 | 330 | */ |
7bc8d985 | 331 | if (dp->b_active) |
008c0481 | 332 | goto done; |
7bc8d985 | 333 | dp->b_active = 1; |
008c0481 | 334 | if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) |
7bc8d985 | 335 | goto done; /* Will redetect error in upstart() soon */ |
008c0481 | 336 | |
7bc8d985 BJ |
337 | /* |
338 | * Do enough of the disk address decoding to determine | |
339 | * which cylinder and sector the request is on. | |
340 | * Then compute the number of the sector SDIST sectors before | |
341 | * the one where the transfer is to start, this being the | |
342 | * point where we wish to attempt to begin the transfer, | |
343 | * allowing approximately SDIST/2 msec for interrupt latency | |
344 | * and preparation of the request. | |
345 | * | |
346 | * If we are on the correct cylinder and the desired sector | |
347 | * lies between SDIST and SDIST+RDIST sectors ahead of us, then | |
348 | * we don't bother to SEARCH but just begin the transfer asap. | |
349 | */ | |
008c0481 BJ |
350 | bn = dkblock(bp); |
351 | cn = bp->b_cylin; | |
352 | sn = bn%(NSECT*NTRAC); | |
353 | sn = (sn+NSECT-SDIST)%NSECT; | |
354 | ||
7bc8d985 BJ |
355 | if (cn - upaddr->updc) |
356 | goto search; /* Not on-cylinder */ | |
008c0481 | 357 | csn = (upaddr->upla>>6) - sn - 1; |
7bc8d985 | 358 | if (csn < 0) |
008c0481 | 359 | csn += NSECT; |
7bc8d985 | 360 | if (csn > NSECT-RDIST) |
008c0481 BJ |
361 | goto done; |
362 | ||
363 | search: | |
364 | upaddr->updc = cn; | |
365 | upaddr->upda = sn; | |
7bc8d985 | 366 | if (cs1del&8) DELAY(500); |
008c0481 | 367 | upaddr->upcs1 = IE|SEARCH|GO; |
7bc8d985 BJ |
368 | if (cs1del&8) DELAY(500); |
369 | /* | |
370 | * Mark this unit busy. | |
371 | */ | |
008c0481 BJ |
372 | unit += DK_N; |
373 | if (unit <= DK_NMAX) { | |
374 | dk_busy |= 1<<unit; | |
375 | dk_numb[unit]++; | |
376 | } | |
377 | return; | |
378 | ||
379 | done: | |
7bc8d985 BJ |
380 | /* |
381 | * This unit is ready to go. Make active == 2 so | |
382 | * we won't get called again (by upintr() because upas&(1<<unit)) | |
383 | * and link us onto the chain of ready disks. | |
384 | */ | |
385 | dp->b_active = 2; | |
008c0481 | 386 | dp->b_forw = NULL; |
7bc8d985 | 387 | if (uptab.b_actf == NULL) |
008c0481 BJ |
388 | uptab.b_actf = dp; |
389 | else | |
390 | uptab.b_actl->b_forw = dp; | |
391 | uptab.b_actl = dp; | |
392 | } | |
393 | ||
394 | /* | |
395 | * Start a transfer; call from top level at spl5() or on interrupt. | |
008c0481 BJ |
396 | */ |
397 | upstart() | |
398 | { | |
399 | register struct buf *bp, *dp; | |
400 | register unit; | |
401 | register struct device *upaddr; | |
402 | daddr_t bn; | |
7bc8d985 | 403 | int dn, sn, tn, cn, cmd; |
008c0481 BJ |
404 | |
405 | if (printsw&2) printf("upstart\n"); | |
406 | loop: | |
7bc8d985 BJ |
407 | /* |
408 | * Pick a drive off the queue of ready drives, and | |
409 | * perform the first transfer on its queue. | |
410 | * | |
411 | * Looping here is completely for the sake of drives which | |
412 | * are not present and on-line, for which we completely clear the | |
413 | * request queue. | |
414 | */ | |
008c0481 BJ |
415 | if ((dp = uptab.b_actf) == NULL) |
416 | return; | |
417 | if ((bp = dp->b_actf) == NULL) { | |
418 | uptab.b_actf = dp->b_forw; | |
419 | goto loop; | |
420 | } | |
7bc8d985 BJ |
421 | /* |
422 | * Mark the controller busy, and multi-part disk address. | |
423 | * Select the unit on which the i/o is to take place. | |
424 | */ | |
008c0481 BJ |
425 | uptab.b_active++; |
426 | unit = minor(bp->b_dev) & 077; | |
427 | dn = dkunit(bp); | |
428 | bn = dkblock(bp); | |
429 | cn = up_sizes[unit&07].cyloff; | |
430 | cn += bn/(NSECT*NTRAC); | |
431 | sn = bn%(NSECT*NTRAC); | |
432 | tn = sn/NSECT; | |
7bc8d985 | 433 | sn %= NSECT; |
008c0481 | 434 | upaddr = UPADDR; |
008c0481 BJ |
435 | if ((upaddr->upcs2 & 07) != dn) { |
436 | upaddr->upcs2 = dn; | |
437 | DELAY(sdelay); | |
438 | nwaitcs2++; | |
439 | } else | |
440 | neasycs2++; | |
7bc8d985 BJ |
441 | up_ubinfo = ubasetup(bp, 1); /* In a funny place for delay... */ |
442 | /* | |
443 | * If drive is not present and on-line, then | |
444 | * get rid of this with an error and loop to get | |
445 | * rid of the rest of its queued requests. | |
446 | * (Then on to any other ready drives.) | |
447 | */ | |
008c0481 BJ |
448 | if ((upaddr->upds & (DPR|MOL)) != (DPR|MOL)) { |
449 | uptab.b_active = 0; | |
450 | uptab.b_errcnt = 0; | |
451 | dp->b_actf = bp->av_forw; | |
7bc8d985 | 452 | dp->b_active = 0; |
008c0481 BJ |
453 | bp->b_flags |= B_ERROR; |
454 | iodone(bp); | |
7bc8d985 | 455 | ubafree(up_ubinfo), up_ubinfo = 0; /* A funny place ... */ |
008c0481 BJ |
456 | goto loop; |
457 | } | |
7bc8d985 BJ |
458 | /* |
459 | * If this is a retry, then with the 16'th retry we | |
460 | * begin to try offsetting the heads to recover the data. | |
461 | */ | |
462 | if (uptab.b_errcnt >= 16) { | |
008c0481 | 463 | upaddr->upof = up_offset[uptab.b_errcnt & 017] | FMT22; |
7bc8d985 | 464 | upaddr->upcs1 = IE|OFFSET|GO; |
008c0481 | 465 | DELAY(idelay); |
7bc8d985 | 466 | while (upaddr->upds & PIP) |
008c0481 BJ |
467 | DELAY(25); |
468 | } | |
7bc8d985 BJ |
469 | /* |
470 | * Now set up the transfer, retrieving the high | |
471 | * 2 bits of the UNIBUS address from the information | |
472 | * returned by ubasetup() for the cs1 register bits 8 and 9. | |
473 | */ | |
008c0481 BJ |
474 | upaddr->updc = cn; |
475 | upaddr->upda = (tn << 8) + sn; | |
476 | upaddr->upba = up_ubinfo; | |
7bc8d985 | 477 | if (cs1del&1) DELAY(500); |
008c0481 | 478 | upaddr->upwc = -bp->b_bcount / sizeof (short); |
7bc8d985 | 479 | cmd = (up_ubinfo >> 8) & 0x300; |
008c0481 | 480 | if (bp->b_flags & B_READ) |
7bc8d985 | 481 | cmd |= IE|RCOM|GO; |
008c0481 | 482 | else |
7bc8d985 BJ |
483 | cmd |= IE|WCOM|GO; |
484 | if (cs1del&1) DELAY(500); | |
485 | upaddr->upcs1 = cmd; | |
486 | if (cs1del&1) DELAY(500); | |
487 | /* | |
488 | * This is a controller busy situation. | |
489 | * Record in dk slot NUP+DK_N (after last drive) | |
490 | * unless there aren't that many slots reserved for | |
491 | * us in which case we record this as a drive busy | |
492 | * (if there is room for that). | |
493 | */ | |
008c0481 BJ |
494 | unit = dn+DK_N; |
495 | if (NUP+DK_N == DK_NMAX) | |
496 | unit = NUP+DK_N; | |
497 | if (unit <= DK_NMAX) { | |
498 | dk_busy |= 1<<unit; | |
499 | dk_numb[unit]++; | |
500 | dk_wds[unit] += bp->b_bcount>>6; | |
501 | } | |
502 | } | |
503 | ||
504 | /* | |
505 | * Handle a device interrupt. | |
506 | * | |
507 | * If the transferring drive needs attention, service it | |
508 | * retrying on error or beginning next transfer. | |
509 | * Service all other ready drives, calling ustart to transfer | |
510 | * their blocks to the ready queue in uptab, and then restart | |
511 | * the controller if there is anything to do. | |
512 | */ | |
513 | upintr() | |
514 | { | |
515 | register struct buf *bp, *dp; | |
516 | register unit; | |
517 | register struct device *upaddr = UPADDR; | |
518 | int as = upaddr->upas & 0377; | |
519 | ||
7bc8d985 BJ |
520 | if (printsw&4) printf("upintr as=%d act %d %d %d\n", as, uptab.b_active, uputab[0].b_active, uputab[1].b_active); |
521 | if (uptab.b_active) { | |
522 | /* | |
523 | * The drive is transferring, thus the hardware | |
524 | * (say the designers) will only interrupt when the transfer | |
525 | * completes; check for it anyways. | |
526 | */ | |
527 | if ((upaddr->upcs1 & RDY) == 0) { | |
528 | printf("upintr b_active && !RDY\n"); | |
529 | goto out; | |
530 | } | |
531 | /* | |
532 | * Mark controller or drive not busy, and check for an | |
533 | * error condition which may have resulted from the transfer. | |
534 | */ | |
008c0481 BJ |
535 | dp = uptab.b_actf; |
536 | bp = dp->b_actf; | |
537 | unit = dkunit(bp); | |
538 | if (DK_N+NUP == DK_NMAX) | |
539 | dk_busy &= ~(1<<(DK_N+NUP)); | |
540 | else if (DK_N+unit <= DK_NMAX) | |
541 | dk_busy &= ~(1<<(DK_N+unit)); | |
542 | if (upaddr->upcs1 & TRE) { | |
7bc8d985 BJ |
543 | /* |
544 | * An error occurred, indeed. Select this unit | |
545 | * to get at the drive status (a SEARCH may have | |
546 | * intervened to change the selected unit), and | |
547 | * wait for the command which caused the interrupt | |
548 | * to complete (DRY). | |
549 | * | |
550 | * WHY IS THE WAIT NECESSARY? | |
551 | */ | |
008c0481 BJ |
552 | if ((upaddr->upcs2 & 07) != unit) { |
553 | upaddr->upcs2 = unit; | |
554 | DELAY(sdelay); | |
555 | nwaitcs2++; | |
556 | } else | |
557 | neasycs2++; | |
7bc8d985 | 558 | while ((upaddr->upds & DRY) == 0) |
008c0481 | 559 | DELAY(25); |
7bc8d985 BJ |
560 | /* |
561 | * After 28 retries (16 w/o servo offsets, and then | |
562 | * 12 with servo offsets), or if we encountered | |
563 | * an error because the drive is write-protected, | |
564 | * give up. Print an error message on the last 2 | |
565 | * retries before a hard failure. | |
566 | */ | |
567 | if (++uptab.b_errcnt > 28 || upaddr->uper1&WLE) | |
008c0481 BJ |
568 | bp->b_flags |= B_ERROR; |
569 | else | |
7bc8d985 BJ |
570 | uptab.b_active = 0; /* To force retry */ |
571 | if (uptab.b_errcnt > 27) | |
008c0481 | 572 | deverror(bp, upaddr->upcs2, upaddr->uper1); |
7bc8d985 BJ |
573 | /* |
574 | * If this was a correctible ECC error, let upecc | |
575 | * do the dirty work to correct it. If upecc | |
576 | * starts another READ for the rest of the data | |
577 | * then it returns 1 (having set uptab.b_active). | |
578 | * Otherwise we are done and fall through to | |
579 | * finish up. | |
580 | */ | |
581 | if ((upaddr->uper1&(DCK|ECH))==DCK && upecc(upaddr, bp)) | |
582 | return; | |
583 | /* | |
584 | * Clear the drive and, every 4 retries, recalibrate | |
585 | * to hopefully help clear up seek positioning problems. | |
586 | */ | |
008c0481 BJ |
587 | upaddr->upcs1 = TRE|IE|DCLR|GO; |
588 | DELAY(idelay); | |
7bc8d985 | 589 | if ((uptab.b_errcnt&07) == 4) { |
008c0481 BJ |
590 | upaddr->upcs1 = RECAL|GO|IE; |
591 | DELAY(idelay); | |
592 | while(upaddr->upds & PIP) | |
593 | DELAY(25); | |
594 | } | |
595 | } | |
7bc8d985 BJ |
596 | /* |
597 | * If we are still noted as active, then no | |
598 | * (further) retries are necessary. | |
599 | * | |
600 | * Make sure the correct unit is selected, | |
601 | * return it to centerline if necessary, and mark | |
602 | * this i/o complete, starting the next transfer | |
603 | * on this drive with the upustart routine (if any). | |
604 | */ | |
605 | if (uptab.b_active) { | |
606 | if ((upaddr->upcs2 & 07) != unit) { | |
607 | upaddr->upcs2 = unit; | |
608 | DELAY(sdelay); | |
609 | nwaitcs2++; | |
610 | } else | |
611 | neasycs2++; | |
612 | if (uptab.b_errcnt >= 16) { | |
613 | upaddr->upcs1 = RTC|GO|IE; | |
008c0481 | 614 | DELAY(idelay); |
7bc8d985 | 615 | while (upaddr->upds & PIP) |
008c0481 BJ |
616 | DELAY(25); |
617 | } | |
618 | uptab.b_active = 0; | |
619 | uptab.b_errcnt = 0; | |
620 | uptab.b_actf = dp->b_forw; | |
621 | dp->b_active = 0; | |
622 | dp->b_errcnt = 0; | |
623 | dp->b_actf = bp->av_forw; | |
7bc8d985 BJ |
624 | bp->b_resid = (-upaddr->upwc * sizeof(short)); |
625 | if (cs1del&2) DELAY(500); | |
626 | upaddr->upcs1 = IE; | |
627 | if (cs1del&2) DELAY(500); | |
008c0481 BJ |
628 | iodone(bp); |
629 | if(dp->b_actf) | |
630 | upustart(unit); | |
631 | } | |
632 | as &= ~(1<<unit); | |
633 | ubafree(up_ubinfo), up_ubinfo = 0; | |
7bc8d985 BJ |
634 | } |
635 | #ifndef notdef | |
636 | else { | |
637 | if (printsw&64) printf("cs1 %o\n", upaddr->upcs1); | |
008c0481 BJ |
638 | if (upaddr->upcs1 & TRE) { |
639 | upaddr->upcs1 = TRE; | |
640 | DELAY(idelay); | |
7bc8d985 | 641 | if (printsw&64) printf("after TRE cs1 %o\n", upaddr->upcs1); |
008c0481 | 642 | } |
008c0481 | 643 | } |
7bc8d985 BJ |
644 | #endif |
645 | /* | |
646 | * If we have a unit with an outstanding SEARCH, | |
647 | * and the hardware indicates the unit requires attention, | |
648 | * the bring the drive to the ready queue. | |
649 | * Finally, if the controller is not transferring | |
650 | * start it if any drives are now ready to transfer. | |
651 | */ | |
652 | for (unit = 0; unit < NUP; unit++) | |
653 | if (as & (1<<unit)) | |
654 | if (uputab[unit].b_active == 1) | |
655 | upustart(unit); | |
656 | else { | |
657 | upaddr->upas = 1<<unit; | |
658 | DELAY(1000); | |
659 | } | |
660 | if (uptab.b_actf && uptab.b_active == 0) | |
661 | upstart(); | |
662 | out: | |
663 | if (cs1del&4) DELAY(500); | |
664 | if ((upaddr->upcs1&IE) == 0) | |
665 | upaddr->upcs1 = IE; | |
666 | if (cs1del&4) DELAY(500); | |
667 | if (printsw&128) printf("exit cs1 %o\n", upaddr->upcs1); | |
008c0481 BJ |
668 | } |
669 | ||
670 | upread(dev) | |
671 | { | |
672 | ||
673 | physio(upstrategy, &rupbuf, dev, B_READ, minphys); | |
674 | } | |
675 | ||
676 | upwrite(dev) | |
677 | { | |
678 | ||
679 | physio(upstrategy, &rupbuf, dev, B_WRITE, minphys); | |
680 | } | |
681 | ||
7bc8d985 BJ |
682 | /* |
683 | * Correct an ECC error, and restart the i/o to complete | |
684 | * the transfer if necessary. This is quite complicated because | |
685 | * the transfer may be going to an odd memory address base and/or | |
686 | * across a page boundary. | |
687 | */ | |
008c0481 BJ |
688 | upecc(up, bp) |
689 | register struct device *up; | |
690 | register struct buf *bp; | |
691 | { | |
692 | struct uba_regs *ubp = (struct uba_regs *)UBA0; | |
7bc8d985 | 693 | register int i; |
008c0481 | 694 | caddr_t addr; |
7bc8d985 | 695 | int reg, bit, byte, npf, mask, o, cmd, ubaddr; |
008c0481 BJ |
696 | int bn, cn, tn, sn; |
697 | ||
698 | if (printsw&8) printf("upecc\n"); | |
699 | /* | |
7bc8d985 BJ |
700 | * Npf is the number of sectors transferred before the sector |
701 | * containing the ECC error, and reg is the UBA register | |
702 | * mapping (the first part of) the transfer. | |
703 | * O is offset within a memory page of the first byte transferred. | |
008c0481 | 704 | */ |
7bc8d985 BJ |
705 | npf = btop((up->upwc * sizeof(short)) + bp->b_bcount) - 1; |
706 | reg = btop(up_ubinfo&0x3ffff) + npf; | |
008c0481 BJ |
707 | o = (int)bp->b_un.b_addr & PGOFSET; |
708 | printf("%D ", bp->b_blkno+npf); | |
709 | prdev("ECC", bp->b_dev); | |
710 | mask = up->upec2; | |
711 | if (mask == 0) { | |
7bc8d985 | 712 | up->upof = FMT22; /* == RTC ???? */ |
008c0481 BJ |
713 | DELAY(idelay); |
714 | return (0); | |
715 | } | |
7bc8d985 BJ |
716 | /* |
717 | * Flush the buffered data path, and compute the | |
718 | * byte and bit position of the error. The variable i | |
719 | * is the byte offset in the transfer, the variable byte | |
720 | * is the offset from a page boundary in main memory. | |
721 | */ | |
722 | ubp->uba_dpr[(up_ubinfo>>28)&0x0f] |= BNE; | |
723 | i = up->upec1 - 1; /* -1 makes 0 origin */ | |
724 | bit = i&07; | |
725 | i = (i&~07)>>3; | |
008c0481 | 726 | byte = i + o; |
7bc8d985 BJ |
727 | /* |
728 | * Correct while possible bits remain of mask. Since mask | |
729 | * contains 11 bits, we continue while the bit offset is > -11. | |
730 | * Also watch out for end of this block and the end of the whole | |
731 | * transfer. | |
732 | */ | |
733 | while (i < 512 && (int)ptob(npf)+i < bp->b_bcount && bit > -11) { | |
734 | addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+ | |
735 | (byte & PGOFSET); | |
736 | putmemc(addr, getmemc(addr)^(mask<<bit)); | |
737 | byte++; | |
738 | i++; | |
739 | bit -= 8; | |
008c0481 | 740 | } |
7bc8d985 | 741 | uptab.b_active++; /* Either complete or continuing... */ |
008c0481 BJ |
742 | if (up->upwc == 0) |
743 | return (0); | |
7bc8d985 BJ |
744 | /* |
745 | * Have to continue the transfer... clear the drive, | |
746 | * and compute the position where the transfer is to continue. | |
747 | * We have completed npf+1 sectors of the transfer already; | |
748 | * restart at offset o of next sector (i.e. in UBA register reg+1). | |
749 | */ | |
750 | up->upcs1 = TRE|IE|DCLR|GO; | |
008c0481 BJ |
751 | DELAY(idelay); |
752 | bn = dkblock(bp); | |
753 | cn = bp->b_cylin; | |
7bc8d985 | 754 | sn = bn%(NSECT*NTRAC) + npf + 1; |
008c0481 BJ |
755 | tn = sn/NSECT; |
756 | sn %= NSECT; | |
7bc8d985 BJ |
757 | cn += tn/NTRAC; |
758 | tn %= NTRAC; | |
008c0481 | 759 | up->updc = cn; |
7bc8d985 BJ |
760 | up->upda = (tn << 8) | sn; |
761 | ubaddr = (int)ptob(reg+1) + o; | |
762 | up->upba = ubaddr; | |
763 | cmd = (ubaddr >> 8) & 0x300; | |
764 | cmd |= IE|GO|RCOM; | |
765 | up->upcs1 = cmd; | |
008c0481 BJ |
766 | return (1); |
767 | } |