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