xref: /csrg-svn/sys/vax/uba/idc.c (revision 6941)
1*6941Ssam /*	idc.c	4.1	82/05/26	*/
2*6941Ssam 
3*6941Ssam #include "rb.h"
4*6941Ssam #if NIDC > 0
5*6941Ssam int idcdebug = 0;
6*6941Ssam #define printd if(idcdebug)printf
7*6941Ssam int idctrb[1000];
8*6941Ssam int *trp = idctrb;
9*6941Ssam #define	trace(a,b) {*trp++ = (int)a; *trp++ = (int)b; if(trp>&idctrb[998])trp=idctrb;}
10*6941Ssam /*
11*6941Ssam  * IDC (RB730) disk driver
12*6941Ssam  *
13*6941Ssam  * There can only ever be one IDC on a machine,
14*6941Ssam  * and only on a VAX-11/730.  We take advantage
15*6941Ssam  * of that to simplify the driver.
16*6941Ssam  *
17*6941Ssam  * TODO:
18*6941Ssam  *	dk_busy
19*6941Ssam  *	ecc
20*6941Ssam  *	dump
21*6941Ssam  */
22*6941Ssam #include "../h/param.h"
23*6941Ssam #include "../h/systm.h"
24*6941Ssam #include "../h/buf.h"
25*6941Ssam #include "../h/conf.h"
26*6941Ssam #include "../h/dir.h"
27*6941Ssam #include "../h/user.h"
28*6941Ssam #include "../h/pte.h"
29*6941Ssam #include "../h/map.h"
30*6941Ssam #include "../h/vm.h"
31*6941Ssam #include "../h/ubareg.h"
32*6941Ssam #include "../h/ubavar.h"
33*6941Ssam #include "../h/dk.h"
34*6941Ssam #include "../h/cpu.h"
35*6941Ssam #include "../h/cmap.h"
36*6941Ssam #include "../h/dkbad.h"
37*6941Ssam 
38*6941Ssam #include "../h/idcreg.h"
39*6941Ssam 
40*6941Ssam struct idc_softc {
41*6941Ssam 	int	sc_bcnt;	/* number of bytes to transfer */
42*6941Ssam 	int	sc_resid;	/* total number of bytes to transfer */
43*6941Ssam 	int	sc_ubaddr;	/* Unibus address of data */
44*6941Ssam 	short	sc_unit;	/* unit doing transfer */
45*6941Ssam 	short	sc_softas;	/* software attention summary bits */
46*6941Ssam 	union idc_dar {
47*6941Ssam 		long	dar_l;
48*6941Ssam 		u_short	dar_w[2];
49*6941Ssam 		u_char	dar_b[4];
50*6941Ssam 	} sc_un;		/* prototype disk address register */
51*6941Ssam } idc_softc;
52*6941Ssam 
53*6941Ssam #define	dar_dar		dar_l		/* the whole disk address */
54*6941Ssam #define	dar_cyl		dar_w[1]	/* cylinder address */
55*6941Ssam #define	dar_trk		dar_b[1]	/* track */
56*6941Ssam #define	dar_sect	dar_b[0]	/* sector */
57*6941Ssam #define	sc_dar		sc_un.dar_dar
58*6941Ssam #define	sc_cyl		sc_un.dar_cyl
59*6941Ssam #define	sc_trk		sc_un.dar_trk
60*6941Ssam #define	sc_sect		sc_un.dar_sect
61*6941Ssam 
62*6941Ssam /* THIS SHOULD BE READ OFF THE PACK, PER DRIVE */
63*6941Ssam struct size {
64*6941Ssam 	daddr_t	nblocks;
65*6941Ssam 	int	cyloff;
66*6941Ssam } rb02_sizes[8] ={
67*6941Ssam 	15884,	0,		/* A=cyl 0 thru 399 */
68*6941Ssam 	4480,	400,		/* B=cyl 400 thru 510 */
69*6941Ssam 	20480,	0,		/* C=cyl 0 thru 511 */
70*6941Ssam 	0,	0,
71*6941Ssam 	0,	0,
72*6941Ssam 	0,	0,
73*6941Ssam 	0,	0,
74*6941Ssam 	0,	0,
75*6941Ssam }, rb80_sizes[8] ={
76*6941Ssam 	15884,	0,		/* A=cyl 0 thru 36 */
77*6941Ssam 	33440,	37,		/* B=cyl 37 thru 114 */
78*6941Ssam 	242606,	0,		/* C=cyl 0 thru 558 */
79*6941Ssam 	0,	0,
80*6941Ssam 	0,	0,
81*6941Ssam 	0,	0,
82*6941Ssam 	82080,	115,		/* G=cyl 115 thru 304 */
83*6941Ssam 	110143,	305,		/* H=cyl 305 thru 558 */
84*6941Ssam };
85*6941Ssam /* END OF STUFF WHICH SHOULD BE READ IN PER DISK */
86*6941Ssam 
87*6941Ssam int	idcprobe(), idcslave(), idcattach(), idcdgo(), idcintr();
88*6941Ssam struct	uba_ctlr *idcminfo[NIDC];
89*6941Ssam struct	uba_device *idcdinfo[NRB];
90*6941Ssam 
91*6941Ssam u_short	idcstd[] = { 0174400, 0};
92*6941Ssam struct	uba_driver idcdriver =
93*6941Ssam  { idcprobe, idcslave, idcattach, idcdgo, idcstd, "rb", idcdinfo, "idc", idcminfo, 0 };
94*6941Ssam struct	buf idcutab[NRB];
95*6941Ssam union	idc_dar idccyl[NRB];
96*6941Ssam 
97*6941Ssam struct	idcst {
98*6941Ssam 	short	nbps;
99*6941Ssam 	short	nsect;
100*6941Ssam 	short	ntrak;
101*6941Ssam 	short	nspc;
102*6941Ssam 	short	ncyl;
103*6941Ssam 	struct	size *sizes;
104*6941Ssam } idcst[] = {
105*6941Ssam 	256, NRB02SECT, NRB02TRK, NRB02SECT*NRB02TRK, NRB02CYL,	rb02_sizes,
106*6941Ssam 	512, NRB80SECT, NRB80TRK, NRB80SECT*NRB80TRK, NRB80CYL,	rb80_sizes,
107*6941Ssam };
108*6941Ssam 
109*6941Ssam struct	buf ridcbuf[NRB];
110*6941Ssam 
111*6941Ssam #define	b_cylin	b_resid
112*6941Ssam 
113*6941Ssam #ifdef INTRLVE
114*6941Ssam daddr_t	dkblock();
115*6941Ssam #endif
116*6941Ssam 
117*6941Ssam int	idcwstart, idcwticks, idcwatch();
118*6941Ssam 
119*6941Ssam idcprobe(reg)
120*6941Ssam 	caddr_t reg;
121*6941Ssam {
122*6941Ssam 	register int br, cvec;
123*6941Ssam 	register struct idcdevice *idcaddr;
124*6941Ssam 
125*6941Ssam #ifdef lint
126*6941Ssam 	br = 0; cvec = br; br = cvec;
127*6941Ssam #endif
128*6941Ssam 	idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200);
129*6941Ssam 	idcaddr->idccsr = IDC_ATTN|IDC_IE;
130*6941Ssam 	while ((idcaddr->idccsr & IDC_CRDY) == 0)
131*6941Ssam 		;
132*6941Ssam 	idcaddr->idccsr = IDC_ATTN|IDC_CRDY;
133*6941Ssam 	return (1);
134*6941Ssam }
135*6941Ssam 
136*6941Ssam idcslave(ui, reg)
137*6941Ssam 	struct uba_device *ui;
138*6941Ssam 	caddr_t reg;
139*6941Ssam {
140*6941Ssam 	register struct idcdevice *idcaddr;
141*6941Ssam 	register int i;
142*6941Ssam 
143*6941Ssam 	idcaddr = (struct idcdevice *)((caddr_t)uba_hd[0].uh_uba + 0x200);
144*6941Ssam 	ui->ui_type = 0;
145*6941Ssam 	idcaddr->idcmpr = IDCGS_GETSTAT;
146*6941Ssam 	idcaddr->idccsr = IDC_GETSTAT|(ui->ui_slave<<8);
147*6941Ssam 	idcwait(idcaddr, 0);
148*6941Ssam 	i = idcaddr->idcmpr;
149*6941Ssam 	idcaddr->idccsr = IDC_CRDY|(1<<(ui->ui_slave+16));
150*6941Ssam 	/* read header to synchronize microcode */
151*6941Ssam 	idcwait(idcaddr, 0);
152*6941Ssam 	idcaddr->idccsr = (ui->ui_slave<<8)|IDC_RHDR;
153*6941Ssam 	idcwait(idcaddr, 0);
154*6941Ssam 	if (idcaddr->idccsr & IDC_ERR)
155*6941Ssam 		return (0);
156*6941Ssam 	i = idcaddr->idcmpr;		/* read header word 1 */
157*6941Ssam 	i = idcaddr->idcmpr;		/* read header word 2 */
158*6941Ssam 	if (idcaddr->idccsr&IDC_R80)
159*6941Ssam 		ui->ui_type = 1;
160*6941Ssam 	return (1);
161*6941Ssam }
162*6941Ssam 
163*6941Ssam idcattach(ui)
164*6941Ssam 	register struct uba_device *ui;
165*6941Ssam {
166*6941Ssam 
167*6941Ssam 	/*
168*6941Ssam 	 * Fix all addresses to correspond
169*6941Ssam 	 * to the "real" IDC address.
170*6941Ssam 	 */
171*6941Ssam 	ui->ui_mi->um_addr = ui->ui_addr = (caddr_t)uba_hd[0].uh_uba + 0x200;
172*6941Ssam 	ui->ui_physaddr = (caddr_t)uba_hd[0].uh_physuba + 0x200;
173*6941Ssam 	if (idcwstart == 0) {
174*6941Ssam 		timeout(idcwatch, (caddr_t)0, hz);
175*6941Ssam 		idcwstart++;
176*6941Ssam 	}
177*6941Ssam 	if (ui->ui_dk >= 0)
178*6941Ssam 		if (ui->ui_type)
179*6941Ssam 			dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB80SECT * 256);
180*6941Ssam 		else
181*6941Ssam 			dk_mspw[ui->ui_dk] = 1.0 / (60 * NRB02SECT * 128);
182*6941Ssam 	idccyl[ui->ui_unit].dar_dar = -1;
183*6941Ssam 	ui->ui_flags = 0;
184*6941Ssam }
185*6941Ssam 
186*6941Ssam idcstrategy(bp)
187*6941Ssam 	register struct buf *bp;
188*6941Ssam {
189*6941Ssam 	register struct uba_device *ui;
190*6941Ssam 	register struct idcst *st;
191*6941Ssam 	register int unit;
192*6941Ssam 	register struct buf *dp;
193*6941Ssam 	int xunit = minor(bp->b_dev) & 07;
194*6941Ssam 	long bn, sz;
195*6941Ssam 
196*6941Ssam 	sz = (bp->b_bcount+511) >> 9;
197*6941Ssam 	unit = dkunit(bp);
198*6941Ssam 	if (unit >= NRB)
199*6941Ssam 		goto bad;
200*6941Ssam 	ui = idcdinfo[unit];
201*6941Ssam 	if (ui == 0 || ui->ui_alive == 0)
202*6941Ssam 		goto bad;
203*6941Ssam 	st = &idcst[ui->ui_type];
204*6941Ssam 	if (bp->b_blkno < 0 ||
205*6941Ssam 	    (bn = dkblock(bp))+sz > st->sizes[xunit].nblocks)
206*6941Ssam 		goto bad;
207*6941Ssam 	if (ui->ui_type == 0)
208*6941Ssam 		bn *= 2;
209*6941Ssam 	bp->b_cylin = bn/st->nspc + st->sizes[xunit].cyloff;
210*6941Ssam 	(void) spl5();
211*6941Ssam 	trace('strt',bp);
212*6941Ssam 	dp = &idcutab[ui->ui_unit];
213*6941Ssam 	disksort(dp, bp);
214*6941Ssam 	if (dp->b_active == 0) {
215*6941Ssam 		trace('!act',dp);
216*6941Ssam 		(void) idcustart(ui);
217*6941Ssam 		bp = &ui->ui_mi->um_tab;
218*6941Ssam 		if (bp->b_actf && bp->b_active == 0)
219*6941Ssam 			(void) idcstart(ui->ui_mi);
220*6941Ssam 	}
221*6941Ssam 	(void) spl0();
222*6941Ssam 	return;
223*6941Ssam 
224*6941Ssam bad:
225*6941Ssam 	bp->b_flags |= B_ERROR;
226*6941Ssam 	iodone(bp);
227*6941Ssam 	return;
228*6941Ssam }
229*6941Ssam 
230*6941Ssam idcustart(ui)
231*6941Ssam 	register struct uba_device *ui;
232*6941Ssam {
233*6941Ssam 	register struct buf *bp, *dp;
234*6941Ssam 	register struct uba_ctlr *um;
235*6941Ssam 	register struct idcdevice *idcaddr;
236*6941Ssam 	register struct idcst *st;
237*6941Ssam 	union idc_dar cyltrk;
238*6941Ssam 	daddr_t bn;
239*6941Ssam 	int unit;
240*6941Ssam 
241*6941Ssam 	if (ui == 0)
242*6941Ssam 		return (0);
243*6941Ssam 	dk_busy &= ~(1<<ui->ui_dk);
244*6941Ssam 	dp = &idcutab[ui->ui_unit];
245*6941Ssam 	um = ui->ui_mi;
246*6941Ssam 	unit = ui->ui_slave;
247*6941Ssam 	trace('ust', dp);
248*6941Ssam 	idcaddr = (struct idcdevice *)um->um_addr;
249*6941Ssam 	if (um->um_tab.b_active) {
250*6941Ssam 		idc_softc.sc_softas |= 1<<unit;
251*6941Ssam 		trace('umac',idc_softc.sc_softas);
252*6941Ssam 		return (0);
253*6941Ssam 	}
254*6941Ssam 	if ((bp = dp->b_actf) == NULL) {
255*6941Ssam 		trace('!bp',0);
256*6941Ssam 		return (0);
257*6941Ssam 	}
258*6941Ssam 	if (dp->b_active) {
259*6941Ssam 		trace('dpac',dp->b_active);
260*6941Ssam 		goto done;
261*6941Ssam 	}
262*6941Ssam 	dp->b_active = 1;
263*6941Ssam 	/* CHECK DRIVE READY? */
264*6941Ssam 	bn = dkblock(bp);
265*6941Ssam 	trace('seek', bn);
266*6941Ssam 	if (ui->ui_type == 0)
267*6941Ssam 		bn *= 2;
268*6941Ssam 	st = &idcst[ui->ui_type];
269*6941Ssam 	cyltrk.dar_cyl = bp->b_cylin;
270*6941Ssam 	cyltrk.dar_trk = (bn / st->nsect) % st->ntrak;
271*6941Ssam 	cyltrk.dar_sect = 0;
272*6941Ssam 	printd("idcustart, unit %d, cyltrk 0x%x\n", unit, cyltrk.dar_dar);
273*6941Ssam 	/*
274*6941Ssam 	 * If on cylinder, no need to seek.
275*6941Ssam 	 */
276*6941Ssam 	if (cyltrk.dar_dar == idccyl[ui->ui_unit].dar_dar)
277*6941Ssam 		goto done;
278*6941Ssam 	/*
279*6941Ssam 	 * RB80 can change heads (tracks) just by loading
280*6941Ssam 	 * the disk address register, perform optimization
281*6941Ssam 	 * here instead of doing a full seek.
282*6941Ssam 	 */
283*6941Ssam 	if (ui->ui_type && cyltrk.dar_cyl == idccyl[ui->ui_unit].dar_cyl) {
284*6941Ssam 		idcaddr->idccsr = IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8);
285*6941Ssam 		idcaddr->idcdar = cyltrk.dar_dar;
286*6941Ssam 		idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;
287*6941Ssam 		goto done;
288*6941Ssam 	}
289*6941Ssam 	/*
290*6941Ssam 	 * Need to do a full seek.  Select the unit, clear
291*6941Ssam 	 * its attention bit, set the command, load the
292*6941Ssam 	 * disk address register, and then go.
293*6941Ssam 	 */
294*6941Ssam 	idcaddr->idccsr =
295*6941Ssam 	    IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));
296*6941Ssam 	idcaddr->idcdar = cyltrk.dar_dar;
297*6941Ssam 	idccyl[ui->ui_unit].dar_dar = cyltrk.dar_dar;
298*6941Ssam 	printd("  seek");
299*6941Ssam 	idcaddr->idccsr = IDC_IE|IDC_SEEK|(unit<<8);
300*6941Ssam 	if (ui->ui_dk >= 0) {
301*6941Ssam 		dk_busy |= 1<<ui->ui_dk;
302*6941Ssam 		dk_seek[ui->ui_dk]++;
303*6941Ssam 	}
304*6941Ssam 	/*
305*6941Ssam 	 * RB80's initiate seeks very quickly.  Wait for it
306*6941Ssam 	 * to come ready rather than taking the interrupt.
307*6941Ssam 	 */
308*6941Ssam 	if (ui->ui_type) {
309*6941Ssam 		if (idcwait(idcaddr, 10) == 0)
310*6941Ssam 			return (1);
311*6941Ssam 		idcaddr->idccsr &= ~IDC_ATTN;
312*6941Ssam 		/* has the seek completed? */
313*6941Ssam 		if (idcaddr->idccsr & IDC_DRDY) {
314*6941Ssam 			printd(", drdy");
315*6941Ssam 			idcaddr->idccsr =
316*6941Ssam 			    IDC_CRDY|IDC_IE|IDC_SEEK|(unit<<8)|(1<<(unit+16));
317*6941Ssam 			goto done;
318*6941Ssam 		}
319*6941Ssam 	}
320*6941Ssam 	printd(", idccsr = 0x%x\n", idcaddr->idccsr);
321*6941Ssam 	return (1);
322*6941Ssam done:
323*6941Ssam 	if (dp->b_active != 2) {
324*6941Ssam 		trace('!=2',dp->b_active);
325*6941Ssam 		dp->b_forw = NULL;
326*6941Ssam 		if (um->um_tab.b_actf == NULL)
327*6941Ssam 			um->um_tab.b_actf = dp;
328*6941Ssam 		else {
329*6941Ssam 			trace('!NUL',um->um_tab.b_actl);
330*6941Ssam 			um->um_tab.b_actl->b_forw = dp;
331*6941Ssam 		}
332*6941Ssam 		um->um_tab.b_actl = dp;
333*6941Ssam 		dp->b_active = 2;
334*6941Ssam 	}
335*6941Ssam 	return (0);
336*6941Ssam }
337*6941Ssam 
338*6941Ssam idcstart(um)
339*6941Ssam 	register struct uba_ctlr *um;
340*6941Ssam {
341*6941Ssam 	register struct buf *bp, *dp;
342*6941Ssam 	register struct uba_device *ui;
343*6941Ssam 	register struct idcdevice *idcaddr;
344*6941Ssam 	register struct idc_softc *sc;
345*6941Ssam 	struct idcst *st;
346*6941Ssam 	daddr_t bn;
347*6941Ssam 	int sn, tn, cmd;
348*6941Ssam 
349*6941Ssam loop:
350*6941Ssam 	if ((dp = um->um_tab.b_actf) == NULL) {
351*6941Ssam 		trace('nodp',um);
352*6941Ssam 		return (0);
353*6941Ssam 	}
354*6941Ssam 	if ((bp = dp->b_actf) == NULL) {
355*6941Ssam 		trace('nobp', dp);
356*6941Ssam 		um->um_tab.b_actf = dp->b_forw;
357*6941Ssam 		goto loop;
358*6941Ssam 	}
359*6941Ssam 	um->um_tab.b_active = 1;
360*6941Ssam 	ui = idcdinfo[dkunit(bp)];
361*6941Ssam 	bn = dkblock(bp);
362*6941Ssam 	trace('star',bp);
363*6941Ssam 	if (ui->ui_type == 0)
364*6941Ssam 		bn *= 2;
365*6941Ssam 	sc = &idc_softc;
366*6941Ssam 	st = &idcst[ui->ui_type];
367*6941Ssam 	sn = bn%st->nspc;
368*6941Ssam 	tn = sn/st->nsect;
369*6941Ssam 	sn %= st->nsect;
370*6941Ssam 	sc->sc_sect = sn;
371*6941Ssam 	sc->sc_trk = tn;
372*6941Ssam 	sc->sc_cyl = bp->b_cylin;
373*6941Ssam 	idcaddr = (struct idcdevice *)ui->ui_addr;
374*6941Ssam 	printd("idcstart, unit %d, dar 0x%x", ui->ui_slave, sc->sc_dar);
375*6941Ssam 	if (bp->b_flags & B_READ)
376*6941Ssam 		cmd = IDC_IE|IDC_READ|(ui->ui_slave<<8);
377*6941Ssam 	else
378*6941Ssam 		cmd = IDC_IE|IDC_WRITE|(ui->ui_slave<<8);
379*6941Ssam 	idcaddr->idccsr = IDC_CRDY|cmd;
380*6941Ssam 	if ((idcaddr->idccsr&IDC_DRDY) == 0) {
381*6941Ssam 		printf("rb%d: not ready\n", dkunit(bp));
382*6941Ssam 		um->um_tab.b_active = 0;
383*6941Ssam 		um->um_tab.b_errcnt = 0;
384*6941Ssam 		dp->b_actf = bp->av_forw;
385*6941Ssam 		dp->b_active = 0;
386*6941Ssam 		bp->b_flags |= B_ERROR;
387*6941Ssam 		iodone(bp);
388*6941Ssam 		goto loop;
389*6941Ssam 	}
390*6941Ssam 	idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
391*6941Ssam 	idccyl[ui->ui_unit].dar_sect = 0;
392*6941Ssam 	sn = (st->nsect - sn) * st->nbps;
393*6941Ssam 	if (sn > bp->b_bcount)
394*6941Ssam 		sn = bp->b_bcount;
395*6941Ssam 	sc->sc_bcnt = sn;
396*6941Ssam 	sc->sc_resid = bp->b_bcount;
397*6941Ssam 	sc->sc_unit = ui->ui_slave;
398*6941Ssam 	printd(", bcr 0x%x, cmd 0x%x\n", sn, cmd);
399*6941Ssam 	um->um_cmd = cmd;
400*6941Ssam 	(void) ubago(ui);
401*6941Ssam 	return (1);
402*6941Ssam }
403*6941Ssam 
404*6941Ssam idcdgo(um)
405*6941Ssam 	register struct uba_ctlr *um;
406*6941Ssam {
407*6941Ssam 	register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;
408*6941Ssam 	register struct idc_softc *sc = &idc_softc;
409*6941Ssam 
410*6941Ssam 	/*
411*6941Ssam 	 * VERY IMPORTANT: must load registers in this order.
412*6941Ssam 	 */
413*6941Ssam 	idcaddr->idcbar = sc->sc_ubaddr = um->um_ubinfo&0x3ffff;
414*6941Ssam 	idcaddr->idcbcr = -sc->sc_bcnt;
415*6941Ssam 	idcaddr->idcdar = sc->sc_dar;
416*6941Ssam 	printd("idcdgo, ubinfo 0x%x, cmd 0x%x\n", um->um_ubinfo, um->um_cmd);
417*6941Ssam 	idcaddr->idccsr = um->um_cmd;
418*6941Ssam 	trace('go', um);
419*6941Ssam 	um->um_tab.b_active = 2;
420*6941Ssam 	/*** CLEAR SPURIOUS ATTN ON R80? ***/
421*6941Ssam }
422*6941Ssam 
423*6941Ssam idcintr(idc)
424*6941Ssam 	int idc;
425*6941Ssam {
426*6941Ssam 	register struct uba_ctlr *um = idcminfo[idc];
427*6941Ssam 	register struct uba_device *ui;
428*6941Ssam 	register struct idcdevice *idcaddr = (struct idcdevice *)um->um_addr;
429*6941Ssam 	register struct idc_softc *sc = &idc_softc;
430*6941Ssam 	register struct buf *bp, *dp;
431*6941Ssam 	struct idcst *st;
432*6941Ssam 	int unit, as, er, cmd, ds = 0;
433*6941Ssam 
434*6941Ssam 	printd("idcintr, idccsr 0x%x", idcaddr->idccsr);
435*6941Ssam top:
436*6941Ssam 	idcwticks = 0;
437*6941Ssam 	trace('intr', um->um_tab.b_active);
438*6941Ssam 	if (um->um_tab.b_active == 2) {
439*6941Ssam 		/*
440*6941Ssam 		 * Process a data transfer complete interrupt.
441*6941Ssam 		 */
442*6941Ssam 		um->um_tab.b_active = 1;
443*6941Ssam 		dp = um->um_tab.b_actf;
444*6941Ssam 		bp = dp->b_actf;
445*6941Ssam 		ui = idcdinfo[dkunit(bp)];
446*6941Ssam 		unit = ui->ui_slave;
447*6941Ssam 		st = &idcst[ui->ui_type];
448*6941Ssam 		idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);
449*6941Ssam 		if ((er = idcaddr->idccsr) & IDC_ERR) {
450*6941Ssam 			if (er & IDC_DE) {
451*6941Ssam 				idcaddr->idcmpr = IDCGS_GETSTAT;
452*6941Ssam 				idcaddr->idccsr = IDC_GETSTAT|(unit<<8);
453*6941Ssam 				idcwait(idcaddr, 0);
454*6941Ssam 				ds = idcaddr->idcmpr;
455*6941Ssam 				idcaddr->idccsr =
456*6941Ssam 				    IDC_IE|IDC_CRDY|(1<<(unit+16));
457*6941Ssam 			}
458*6941Ssam 			printd(", er 0x%x, ds 0x%x", er, ds);
459*6941Ssam 			if (ds & IDCDS_WL) {
460*6941Ssam 				printf("rb%d: write locked\n", dkunit(bp));
461*6941Ssam 				bp->b_flags |= B_ERROR;
462*6941Ssam 			} else if (++um->um_tab.b_errcnt > 28 || er&IDC_HARD) {
463*6941Ssam hard:
464*6941Ssam 				harderr(bp, "rb");
465*6941Ssam 				printf("csr=%b ds=%b\n", er, IDCCSR_BITS, ds,
466*6941Ssam 				    ui->ui_type?IDCRB80DS_BITS:IDCRB02DS_BITS);
467*6941Ssam 				bp->b_flags |= B_ERROR;
468*6941Ssam 			} else if (er & IDC_DCK) {
469*6941Ssam 				switch (er & IDC_ECS) {
470*6941Ssam 				case IDC_ECS_NONE:
471*6941Ssam 					break;
472*6941Ssam 				case IDC_ECS_SOFT:
473*6941Ssam 					idcecc(ui);
474*6941Ssam 					break;
475*6941Ssam 				case IDC_ECS_HARD:
476*6941Ssam 				default:
477*6941Ssam 					goto hard;
478*6941Ssam 				}
479*6941Ssam 			} else
480*6941Ssam 				/* recoverable error, set up for retry */
481*6941Ssam 				goto seek;
482*6941Ssam 		}
483*6941Ssam 		if ((sc->sc_resid -= sc->sc_bcnt) != 0) {
484*6941Ssam 			sc->sc_ubaddr += sc->sc_bcnt;
485*6941Ssam 			/*
486*6941Ssam 			 * Current transfer is complete, have
487*6941Ssam 			 * we overflowed to the next track?
488*6941Ssam 			 */
489*6941Ssam 			if ((sc->sc_sect += sc->sc_bcnt/st->nbps) == st->nsect) {
490*6941Ssam 				sc->sc_sect = 0;
491*6941Ssam 				if (++sc->sc_trk == st->ntrak) {
492*6941Ssam 					sc->sc_trk = 0;
493*6941Ssam 					sc->sc_cyl++;
494*6941Ssam 				} else if (ui->ui_type) {
495*6941Ssam 					/*
496*6941Ssam 					 * RB80 can change heads just by
497*6941Ssam 					 * loading the disk address register.
498*6941Ssam 					 */
499*6941Ssam 					idcaddr->idccsr = IDC_SEEK|IDC_CRDY|
500*6941Ssam 					    IDC_IE|(unit<<8);
501*6941Ssam 					printd(", change to track 0x%x", sc->sc_dar);
502*6941Ssam 					idcaddr->idcdar = sc->sc_dar;
503*6941Ssam 					idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
504*6941Ssam 					idccyl[ui->ui_unit].dar_sect = 0;
505*6941Ssam 					goto cont;
506*6941Ssam 				}
507*6941Ssam 				/*
508*6941Ssam 				 * Changing tracks on RB02 or cylinders
509*6941Ssam 				 * on RB80, start a seek.
510*6941Ssam 				 */
511*6941Ssam seek:
512*6941Ssam 				cmd = IDC_IE|IDC_SEEK|(unit<<8);
513*6941Ssam 				idcaddr->idccsr = cmd|IDC_CRDY;
514*6941Ssam 				idcaddr->idcdar = sc->sc_dar;
515*6941Ssam 				printd(", seek to 0x%x\n", sc->sc_dar);
516*6941Ssam 				idccyl[ui->ui_unit].dar_dar = sc->sc_dar;
517*6941Ssam 				idccyl[ui->ui_unit].dar_sect = 0;
518*6941Ssam 				sc->sc_bcnt = 0;
519*6941Ssam 				idcaddr->idccsr = cmd;
520*6941Ssam 				if (ui->ui_type) {
521*6941Ssam 					if (idcwait(idcaddr, 10) == 0)
522*6941Ssam 						return;
523*6941Ssam 					idcaddr->idccsr &= ~IDC_ATTN;
524*6941Ssam 					if (idcaddr->idccsr & IDC_DRDY)
525*6941Ssam 						goto top;
526*6941Ssam 				}
527*6941Ssam 			} else {
528*6941Ssam 				/*
529*6941Ssam 				 * Continue transfer on current track.
530*6941Ssam 				 */
531*6941Ssam cont:
532*6941Ssam 				sc->sc_bcnt = (st->nsect-sc->sc_sect)*st->nbps;
533*6941Ssam 				if (sc->sc_bcnt > sc->sc_resid)
534*6941Ssam 					sc->sc_bcnt = sc->sc_resid;
535*6941Ssam 				if (bp->b_flags & B_READ)
536*6941Ssam 					cmd = IDC_IE|IDC_READ|(unit<<8);
537*6941Ssam 				else
538*6941Ssam 					cmd = IDC_IE|IDC_WRITE|(unit<<8);
539*6941Ssam 				idcaddr->idccsr = cmd|IDC_CRDY;
540*6941Ssam 				idcaddr->idcbar = sc->sc_ubaddr;
541*6941Ssam 				idcaddr->idcbcr = -sc->sc_bcnt;
542*6941Ssam 				idcaddr->idcdar = sc->sc_dar;
543*6941Ssam 				printd(", continue I/O 0x%x, 0x%x\n", sc->sc_dar, sc->sc_bcnt);
544*6941Ssam 				idcaddr->idccsr = cmd;
545*6941Ssam 				um->um_tab.b_active = 2;
546*6941Ssam 			}
547*6941Ssam 			return;
548*6941Ssam 		}
549*6941Ssam 		/*
550*6941Ssam 		 * Entire transfer is done, clean up.
551*6941Ssam 		 */
552*6941Ssam 		ubadone(um);
553*6941Ssam 		dk_busy &= ~(1 << ui->ui_dk);
554*6941Ssam 		um->um_tab.b_active = 0;
555*6941Ssam 		um->um_tab.b_errcnt = 0;
556*6941Ssam 		um->um_tab.b_actf = dp->b_forw;
557*6941Ssam 		dp->b_active = 0;
558*6941Ssam 		dp->b_errcnt = 0;
559*6941Ssam 		dp->b_actf = bp->av_forw;
560*6941Ssam 		trace('done', dp); trace(um->um_tab.b_actf, dp->b_actf);
561*6941Ssam 		bp->b_resid = sc->sc_resid;
562*6941Ssam 		printd(", iodone, resid 0x%x\n", bp->b_resid);
563*6941Ssam 		iodone(bp);
564*6941Ssam 		if (dp->b_actf)
565*6941Ssam 			if (idcustart(ui))
566*6941Ssam 				return;
567*6941Ssam 	} else if (um->um_tab.b_active == 1) {
568*6941Ssam 		/*
569*6941Ssam 		 * Got an interrupt while setting up for a command
570*6941Ssam 		 * or doing a mid-transfer seek.  Save any attentions
571*6941Ssam 		 * for later and process a mid-transfer seek complete.
572*6941Ssam 		 */
573*6941Ssam 		as = idcaddr->idccsr;
574*6941Ssam 		idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);
575*6941Ssam 		as = (as >> 16) & 0xf;
576*6941Ssam 		unit = sc->sc_unit;
577*6941Ssam 		sc->sc_softas |= as & ~(1<<unit);
578*6941Ssam 		if (as & (1<<unit)) {
579*6941Ssam 			printd(", seek1 complete");
580*6941Ssam 			um->um_tab.b_active = 2;
581*6941Ssam 			goto top;
582*6941Ssam 		}
583*6941Ssam 		printd(", as1 %o\n", as);
584*6941Ssam 		return;
585*6941Ssam 	}
586*6941Ssam 	/*
587*6941Ssam 	 * Process any seek initiated or complete interrupts.
588*6941Ssam 	 */
589*6941Ssam 	as = idcaddr->idccsr;
590*6941Ssam 	idcaddr->idccsr = IDC_IE|IDC_CRDY|(as&IDC_ATTN);
591*6941Ssam 	as = ((as >> 16) & 0xf) | sc->sc_softas;
592*6941Ssam 	sc->sc_softas = 0;
593*6941Ssam 	trace('as', as);
594*6941Ssam 	printd(", as %o", as);
595*6941Ssam 	for (unit = 0; unit < NRB; unit++)
596*6941Ssam 		if (as & (1<<unit)) {
597*6941Ssam 			as &= ~(1<<unit);
598*6941Ssam 			idcaddr->idccsr = IDC_IE|IDC_CRDY|(unit<<8);
599*6941Ssam 			ui = idcdinfo[unit];
600*6941Ssam 			if (ui) {
601*6941Ssam 				printd(", attn unit %d", unit);
602*6941Ssam 				if (idcaddr->idccsr & IDC_DRDY)
603*6941Ssam 					if (idcustart(ui)) {
604*6941Ssam 						sc->sc_softas = as;
605*6941Ssam 						return;
606*6941Ssam 					}
607*6941Ssam 			} else {
608*6941Ssam 				printd(", unsol. intr. unit %d", unit);
609*6941Ssam 			}
610*6941Ssam 		}
611*6941Ssam 	printd("\n");
612*6941Ssam 	if (um->um_tab.b_actf && um->um_tab.b_active == 0) {
613*6941Ssam 		trace('stum',um->um_tab.b_actf);
614*6941Ssam 		idcstart(um);
615*6941Ssam 	}
616*6941Ssam }
617*6941Ssam 
618*6941Ssam idcwait(addr, cnt)
619*6941Ssam 	register struct idcdevice *addr;
620*6941Ssam 	register int cnt;
621*6941Ssam {
622*6941Ssam 	register int i;
623*6941Ssam 
624*6941Ssam 	while (--cnt && (addr->idccsr & IDC_CRDY) == 0)
625*6941Ssam 		for (i = 10; i; i--)
626*6941Ssam 			;
627*6941Ssam 	return (cnt);
628*6941Ssam }
629*6941Ssam 
630*6941Ssam idcread(dev)
631*6941Ssam 	dev_t dev;
632*6941Ssam {
633*6941Ssam 	register int unit = minor(dev) >> 3;
634*6941Ssam 
635*6941Ssam 	if (unit >= NRB)
636*6941Ssam 		u.u_error = ENXIO;
637*6941Ssam 	else
638*6941Ssam 		physio(idcstrategy, &ridcbuf[unit], dev, B_READ, minphys);
639*6941Ssam }
640*6941Ssam 
641*6941Ssam idcwrite(dev)
642*6941Ssam 	dev_t dev;
643*6941Ssam {
644*6941Ssam 	register int unit = minor(dev) >> 3;
645*6941Ssam 
646*6941Ssam 	if (unit >= NRB)
647*6941Ssam 		u.u_error = ENXIO;
648*6941Ssam 	else
649*6941Ssam 		physio(idcstrategy, &ridcbuf[unit], dev, B_WRITE, minphys);
650*6941Ssam }
651*6941Ssam 
652*6941Ssam idcecc(ui)
653*6941Ssam 	register struct uba_device *ui;
654*6941Ssam {
655*6941Ssam 	register struct idcdevice *idc = (struct idcdevice *)ui->ui_addr;
656*6941Ssam 	register struct buf *bp = idcutab[ui->ui_unit].b_actf;
657*6941Ssam 	register struct uba_ctlr *um = ui->ui_mi;
658*6941Ssam 	register struct idcst *st;
659*6941Ssam 	register int i;
660*6941Ssam 	struct uba_regs *ubp = ui->ui_hd->uh_uba;
661*6941Ssam 	int bit, byte, mask;
662*6941Ssam 	caddr_t addr;
663*6941Ssam 	int reg, npf, o;
664*6941Ssam 	int cn, tn, sn;
665*6941Ssam 
666*6941Ssam 	printf("idcecc: HELP!\n");
667*6941Ssam 	npf = btop(idc->idcbcr + idc_softc.sc_bcnt) - 1;;
668*6941Ssam 	reg = btop(idc_softc.sc_ubaddr) + npf;
669*6941Ssam 	o = (int)bp->b_un.b_addr & PGOFSET;
670*6941Ssam 	st = &idcst[ui->ui_type];
671*6941Ssam 	cn = idc_softc.sc_cyl;
672*6941Ssam 	tn = idc_softc.sc_trk;
673*6941Ssam 	sn = idc_softc.sc_sect;
674*6941Ssam 	um->um_tab.b_active = 1;	/* Either complete or continuing... */
675*6941Ssam 	printf("rb%d%c: soft ecc sn%d\n", dkunit(bp),
676*6941Ssam 	    'a'+(minor(bp->b_dev)&07),
677*6941Ssam 	    (cn*st->ntrak + tn) * st->nsect + sn + npf);
678*6941Ssam 	mask = idc->idceccpat;
679*6941Ssam 	i = idc->idceccpos - 1;		/* -1 makes 0 origin */
680*6941Ssam 	bit = i&07;
681*6941Ssam 	i = (i&~07)>>3;
682*6941Ssam 	byte = i + o;
683*6941Ssam 	while (i < 512 && (int)ptob(npf)+i < idc_softc.sc_bcnt && bit > -11) {
684*6941Ssam 		addr = ptob(ubp->uba_map[reg+btop(byte)].pg_pfnum)+
685*6941Ssam 		    (byte & PGOFSET);
686*6941Ssam 		putmemc(addr, getmemc(addr)^(mask<<bit));
687*6941Ssam 		byte++;
688*6941Ssam 		i++;
689*6941Ssam 		bit -= 8;
690*6941Ssam 	}
691*6941Ssam 	idc_softc.sc_bcnt += idc->idcbcr;
692*6941Ssam 	um->um_tab.b_errcnt = 0;	/* error has been corrected */
693*6941Ssam 	return;
694*6941Ssam }
695*6941Ssam 
696*6941Ssam idcreset(uban)
697*6941Ssam 	int uban;
698*6941Ssam {
699*6941Ssam 	register struct uba_ctlr *um;
700*6941Ssam 	register struct uba_device *ui;
701*6941Ssam 	register unit;
702*6941Ssam 
703*6941Ssam 	if ((um = idcminfo[0]) == 0 || um->um_ubanum != uban ||
704*6941Ssam 	    um->um_alive == 0)
705*6941Ssam 		return;
706*6941Ssam 	printf(" idc0");
707*6941Ssam 	um->um_tab.b_active = 0;
708*6941Ssam 	um->um_tab.b_actf = um->um_tab.b_actl = 0;
709*6941Ssam 	if (um->um_ubinfo) {
710*6941Ssam 		printf("<%d>", (um->um_ubinfo>>28)&0xf);
711*6941Ssam 		ubadone(um);
712*6941Ssam 	}
713*6941Ssam 	for (unit = 0; unit < NRB; unit++) {
714*6941Ssam 		if ((ui = idcdinfo[unit]) == 0 || ui->ui_alive == 0)
715*6941Ssam 			continue;
716*6941Ssam 		idcutab[unit].b_active = 0;
717*6941Ssam 		(void) idcustart(ui);
718*6941Ssam 	}
719*6941Ssam 	(void) idcstart(um);
720*6941Ssam }
721*6941Ssam 
722*6941Ssam idcwatch()
723*6941Ssam {
724*6941Ssam 	register struct uba_ctlr *um;
725*6941Ssam 	register unit;
726*6941Ssam 
727*6941Ssam 	timeout(idcwatch, (caddr_t)0, hz);
728*6941Ssam 	um = idcminfo[0];
729*6941Ssam 	if (um == 0 || um->um_alive == 0)
730*6941Ssam 		return;
731*6941Ssam 	if (um->um_tab.b_active == 0) {
732*6941Ssam 		for (unit = 0; unit < NRB; unit++)
733*6941Ssam 			if (idcutab[unit].b_active)
734*6941Ssam 				goto active;
735*6941Ssam 		idcwticks = 0;
736*6941Ssam 		return;
737*6941Ssam 	}
738*6941Ssam active:
739*6941Ssam 	idcwticks++;
740*6941Ssam 	if (idcwticks >= 20) {
741*6941Ssam 		idcwticks = 0;
742*6941Ssam 		printf("idc0: lost interrupt\n");
743*6941Ssam 		idcintr(0);
744*6941Ssam 	}
745*6941Ssam }
746*6941Ssam 
747*6941Ssam idcdump(dev)
748*6941Ssam 	dev_t dev;
749*6941Ssam {
750*6941Ssam #ifdef notdef
751*6941Ssam 	struct idcdevice *idcaddr;
752*6941Ssam 	char *start;
753*6941Ssam 	int num, blk, unit, dbsize;
754*6941Ssam 	struct size *sizes;
755*6941Ssam 	register struct uba_regs *uba;
756*6941Ssam 	register struct uba_device *ui;
757*6941Ssam 	struct idcst *st;
758*6941Ssam 
759*6941Ssam 	unit = minor(dev) >> 3;
760*6941Ssam 	if (unit >= NRB)
761*6941Ssam 		return (ENXIO);
762*6941Ssam #define	phys(cast, addr) ((cast)((int)addr & 0x7fffffff))
763*6941Ssam 	ui = phys(struct uba_device *, idcdinfo[unit]);
764*6941Ssam 	if (ui->ui_alive == 0)
765*6941Ssam 		return (ENXIO);
766*6941Ssam 	uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba;
767*6941Ssam 	ubainit(uba);
768*6941Ssam 	idcaddr = (struct idcdevice *)ui->ui_physaddr;
769*6941Ssam 	num = maxfree;
770*6941Ssam 	start = 0;
771*6941Ssam /***
772*6941Ssam 	idcaddr->idccs1 = IDC_CCLR;
773*6941Ssam 	idcaddr->idccs2 = unit;
774*6941Ssam 	idcaddr->idccs1 = idctypes[ui->ui_type]|IDC_DCLR|IDC_GO;
775*6941Ssam 	idcwait(idcaddr);
776*6941Ssam 	dbsize = 20 or 31;
777*6941Ssam ***/
778*6941Ssam 	st = &idcst[ui->ui_type];
779*6941Ssam 	sizes = phys(struct size *, st->sizes);
780*6941Ssam 	if (dumplo < 0 || dumplo + num >= sizes[minor(dev)&07].nblocks)
781*6941Ssam 		return (EINVAL);
782*6941Ssam 	while (num > 0) {
783*6941Ssam 		register struct pte *io;
784*6941Ssam 		register int i;
785*6941Ssam 		int cn, sn, tn;
786*6941Ssam 		daddr_t bn;
787*6941Ssam 
788*6941Ssam 		blk = num > dbsize ? dbsize : num;
789*6941Ssam 		io = uba->uba_map;
790*6941Ssam 		for (i = 0; i < blk; i++)
791*6941Ssam 			*(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV;
792*6941Ssam 		*(int *)io = 0;
793*6941Ssam 		bn = dumplo + btop(start);
794*6941Ssam 		cn = bn/st->nspc + sizes[minor(dev)&07].cyloff;
795*6941Ssam 		sn = bn%st->nspc;
796*6941Ssam 		tn = sn/st->nsect;
797*6941Ssam 		sn = sn%st->nsect;
798*6941Ssam /***
799*6941Ssam 		idcaddr->idccyl = cn;
800*6941Ssam 		rp = (short *) &idcaddr->idcda;
801*6941Ssam 		*rp = (tn << 8) + sn;
802*6941Ssam 		*--rp = 0;
803*6941Ssam 		*--rp = -blk*NBPG / sizeof (short);
804*6941Ssam 		*--rp = idctypes[ui->ui_type]|IDC_GO|IDC_WRITE;
805*6941Ssam 		idcwait(idcaddr);
806*6941Ssam ***/
807*6941Ssam 		if (idcaddr->idccsr & IDC_ERR)
808*6941Ssam 			return (EIO);
809*6941Ssam 		start += blk*NBPG;
810*6941Ssam 		num -= blk;
811*6941Ssam 	}
812*6941Ssam 	return (0);
813*6941Ssam #else
814*6941Ssam 	return (ENXIO);
815*6941Ssam #endif
816*6941Ssam }
817*6941Ssam #endif
818