xref: /csrg-svn/sys/tahoe/vba/vd.c (revision 30370)
1*30370Skarels /*	vd.c	1.13	87/01/11	*/
224004Ssam 
329564Ssam #include "dk.h"
424004Ssam #if NVD > 0
524004Ssam /*
629564Ssam  * VDDC - Versabus SMD/SMDE driver.
725675Ssam  */
825877Ssam #ifdef VDDCPERF
925877Ssam #define	DOSCOPE
1025877Ssam #endif
1125877Ssam 
1225675Ssam #include "param.h"
1325675Ssam #include "buf.h"
1425675Ssam #include "cmap.h"
1525675Ssam #include "conf.h"
1625675Ssam #include "dir.h"
1729564Ssam #include "dkstat.h"
1825675Ssam #include "map.h"
1925675Ssam #include "systm.h"
2025675Ssam #include "user.h"
2125675Ssam #include "vmmac.h"
2225675Ssam #include "proc.h"
2325675Ssam #include "uio.h"
24*30370Skarels #include "syslog.h"
25*30370Skarels #include "kernel.h"
2624004Ssam 
2729951Skarels #include "../tahoe/cpu.h"
2829951Skarels #include "../tahoe/mtpr.h"
2929951Skarels #include "../tahoe/pte.h"
3029951Skarels 
3125675Ssam #include "../tahoevba/vbavar.h"
3225675Ssam #define	VDGENDATA
3325928Ssam #include "../tahoevba/vdreg.h"
3425675Ssam #undef VDGENDATA
3525877Ssam #include "../tahoevba/scope.h"
3624004Ssam 
3725925Ssam #define	VDMAXIO		(MAXBPTE*NBPG)
3825675Ssam #define	DUMPSIZE	64	/* controller limit */
3924004Ssam 
4024004Ssam #define VDUNIT(x)	(minor(x) >> 3)
4125675Ssam #define FILSYS(x)	(minor(x) & 0x07)
4225675Ssam #define PHYS(x)		(vtoph((struct proc *)0, (unsigned)(x)))
4324004Ssam 
4425675Ssam #define CTLR_ERROR	1
4525675Ssam #define DRIVE_ERROR	2
4625675Ssam #define HARD_DATA_ERROR	3
4725675Ssam #define SOFT_DATA_ERROR	4
4829921Skarels #define	WRITE_PROTECT	5
4924004Ssam 
5025675Ssam #define b_cylin	b_resid
5125675Ssam #define b_daddr	b_error
5224004Ssam 
5324004Ssam struct	vba_ctlr *vdminfo[NVD];
5429564Ssam struct  vba_device *vddinfo[NDK];
5525675Ssam int	vdprobe(), vdslave(), vdattach(), vddgo();
5625675Ssam struct	vba_driver vddriver =
5729564Ssam     { vdprobe, vdslave, vdattach, vddgo, vddcaddr, "dk",
5825675Ssam       vddinfo, "vd", vdminfo };
5924004Ssam 
6024004Ssam /*
6125675Ssam  * Per-drive state.
6225675Ssam  */
6325675Ssam typedef struct {
6425675Ssam 	struct	buf raw_q_element;
6525675Ssam 	short	sec_per_blk;
6625675Ssam 	short	sec_per_cyl;
6725675Ssam 	char	status;
6825675Ssam 	struct	buf xfer_queue;
6925675Ssam 	int	drive_type;
7025675Ssam 	fs_tab	info;
7125675Ssam } unit_tab;
7224004Ssam 
7324004Ssam /*
7425675Ssam  * Per-controller state.
7525675Ssam  */
7625675Ssam typedef struct {
7725675Ssam 	char	ctlr_type;	/* controller type */
7825925Ssam 	struct	pte *map;	/* i/o page map */
7925925Ssam 	caddr_t	utl;		/* mapped i/o space */
8025675Ssam 	u_int	cur_slave:8;	/* last active unit number */
8129921Skarels 	u_int	int_expected:1;	/* expect an interrupt */
8225675Ssam 	u_int	ctlr_started:1;	/* start command was issued */
8325675Ssam 	u_int	overlap_seeks:1;/* should overlap seeks */
8425925Ssam 	u_int	initdone:1;	/* controller initialization completed */
8525675Ssam 	u_int	off_cylinder:16;/* off cylinder bit map */
8625675Ssam 	u_int	unit_type[16];	/* slave types */
8725675Ssam 	u_int	cur_cyl[16];	/* cylinder last selected */
8825675Ssam 	long	cur_trk[16];	/* track last selected */
8925675Ssam 	fmt_mdcb ctlr_mdcb;	/* controller mdcb */
9025675Ssam 	fmt_dcb	ctlr_dcb;	/* r/w dcb */
9125675Ssam 	fmt_dcb	seek_dcb[4];	/* dcbs for overlapped seeks */
9225950Ssam 	caddr_t	rawbuf;		/* buffer for raw+swap i/o */
9325675Ssam } ctlr_tab;
9424004Ssam 
9525925Ssam ctlr_tab vdctlr_info[NVD];
9629564Ssam unit_tab vdunit_info[NDK];
9724004Ssam 
9824004Ssam /*
9925675Ssam  * See if the controller is really there; if so, initialize it.
10025675Ssam  */
10125857Ssam vdprobe(reg, vm)
10225857Ssam 	caddr_t reg;
10325857Ssam 	struct vba_ctlr *vm;
10425675Ssam {
10525857Ssam 	register br, cvec;		/* must be r12, r11 */
10625925Ssam 	register cdr *addr = (cdr *)reg;
10725925Ssam 	register ctlr_tab *ci;
10825925Ssam 	int i;
10925857Ssam 
110*30370Skarels #ifdef lint
111*30370Skarels 	br = 0; cvec = br; br = cvec;
112*30370Skarels 	vdintr(0);
113*30370Skarels #endif
11425857Ssam 	if (badaddr((caddr_t)reg, 2))
11525675Ssam 		return (0);
11625925Ssam 	ci = &vdctlr_info[vm->um_ctlr];
11725925Ssam 	addr->cdr_reset = 0xffffffff;
11825675Ssam 	DELAY(1000000);
11925925Ssam 	if (addr->cdr_reset != (unsigned)0xffffffff) {
12025925Ssam 		ci->ctlr_type = SMDCTLR;
12125925Ssam 		ci->overlap_seeks = 0;
12225675Ssam 		DELAY(1000000);
12325675Ssam 	} else {
12425925Ssam 		ci->overlap_seeks = 1;
12525925Ssam 		ci->ctlr_type = SMD_ECTLR;
12625925Ssam 		addr->cdr_reserved = 0x0;
12725675Ssam 		DELAY(3000000);
12825925Ssam 		addr->cdr_csr = 0;
12925925Ssam 		addr->mdcb_tcf = AM_ENPDA;
13025925Ssam 		addr->dcb_tcf = AM_ENPDA;
13125925Ssam 		addr->trail_tcf = AM_ENPDA;
13225925Ssam 		addr->data_tcf = AM_ENPDA;
13329921Skarels 		addr->cdr_ccf = CCF_SEN | CCF_DER | CCF_STS |
13429921Skarels 		    XMD_32BIT | BSZ_16WRD |
13525925Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
13625675Ssam 	}
13725925Ssam 	/*
13825950Ssam 	 * Allocate page tables and i/o buffer.
13925925Ssam 	 */
14025925Ssam 	vbmapalloc(btoc(VDMAXIO)+1, &ci->map, &ci->utl);
14125950Ssam 	ci->rawbuf = calloc(VDMAXIO);
14225925Ssam 	/*
14325925Ssam 	 * Initialize all the drives to be of an unknown type.
14425925Ssam 	 */
14525925Ssam 	for (i = 0; i < 15; i++)
14625925Ssam 		ci->unit_type[i] = UNKNOWN;
14725857Ssam 	br = 0x17, cvec = 0xe0 + vm->um_ctlr;	/* XXX */
14825925Ssam 	return (sizeof (*addr));
14925675Ssam }
15024004Ssam 
15124004Ssam /*
15225675Ssam  * See if a drive is really there
15325675Ssam  * Try to reset/configure the drive, then test its status.
15425675Ssam  */
15525675Ssam vdslave(vi, addr)
15625675Ssam 	register struct vba_device *vi;
15725675Ssam 	register cdr *addr;
15825675Ssam {
15925675Ssam 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
16025675Ssam 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
16125675Ssam 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
16225675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
16325675Ssam 	register int type;
16424004Ssam 
16525925Ssam 	if (!ci->initdone) {
16625925Ssam 		printf("vd%d: %s controller\n", vi->ui_ctlr,
167*30370Skarels 		    ci->ctlr_type == SMDCTLR ? "VDDC" : "SMDE");
16825925Ssam 		if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, INIT, 10) &
16925925Ssam 		    HRDERR) {
17025925Ssam 			printf("vd%d: init error\n", vi->ui_ctlr);
17125675Ssam 			return (0);
17225675Ssam 		}
17325925Ssam 		if (vdnotrailer(addr, vi->ui_ctlr, vi->ui_slave, DIAG, 10) &
17425925Ssam 		    HRDERR) {
17525925Ssam 			printf("vd%d: diagnostic error\n", vi->ui_ctlr);
17625675Ssam 			return (0);
17725675Ssam 		}
17825925Ssam 		ci->initdone = 1;
17925675Ssam 	}
18025675Ssam 	/*
18125675Ssam 	 * Seek on all drive types starting from the largest one.
18225675Ssam 	 * a successful seek to the last sector/cylinder/track verifies
18325675Ssam 	 * the drive type connected to this port.
18425675Ssam 	 */
18525675Ssam 	for (type = 0; type < nvddrv; type++) {
18625675Ssam 		/* XXX */
18725675Ssam 		if (ci->ctlr_type == SMDCTLR && vdst[type].nsec != 32)
18825675Ssam 			continue;
18925675Ssam 		/* XXX */
190*30370Skarels 		if (!vdconfigure_drive(addr, vi->ui_ctlr, vi->ui_slave, type))
19125675Ssam 			return (0);
19225675Ssam 		dcb->opcode = (short)RD;
19325675Ssam 		dcb->intflg = NOINT;
19425675Ssam 		dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
19525675Ssam 		dcb->operrsta = 0;
19625675Ssam 		dcb->devselect = (char)(vi->ui_slave);
19725675Ssam 		dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
19825675Ssam 		dcb->trail.rwtrail.memadr = (char *)PHYS(ci->rawbuf);
19925675Ssam 		dcb->trail.rwtrail.wcount = vdst[type].secsize/sizeof(short);
20025675Ssam 		dcb->trail.rwtrail.disk.cylinder = vdst[type].ncyl - 2;
20125675Ssam 		dcb->trail.rwtrail.disk.track = vdst[type].ntrak - 1;
20225675Ssam 		dcb->trail.rwtrail.disk.sector = vdst[type].nsec - 1;
20325675Ssam 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
20425675Ssam 		mdcb->vddcstat = 0;
20525675Ssam 		VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
20625925Ssam 		if (!vdpoll(ci, addr, 60))
20725675Ssam 			printf(" during probe\n");
20825675Ssam 		if ((dcb->operrsta&HRDERR) == 0)
20925675Ssam 			break;
21025675Ssam 	}
21125675Ssam 	if (type >= nvddrv) {
21225675Ssam 		/*
21325675Ssam 		 * If reached here, a drive which is not defined in the
21429921Skarels 		 * 'vdst' tables is connected. Cannot set its type.
21525675Ssam 		 */
21629564Ssam 		printf("dk%d: unknown drive type\n", vi->ui_unit);
21725675Ssam 		return (0);
21825675Ssam 	}
21925675Ssam 	ui->drive_type = type;
22025675Ssam 	ui->info = vdst[type];
22125675Ssam 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
22225675Ssam 	vi->ui_type = type;
22325675Ssam  	vi->ui_dk = 1;
22425675Ssam 	return (1);
22524004Ssam }
22624004Ssam 
227*30370Skarels vdconfigure_drive(addr, ctlr, slave, type)
22825675Ssam 	register cdr *addr;
229*30370Skarels 	int ctlr, slave, type;
23024004Ssam {
23125675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
23225675Ssam 
23325675Ssam 	ci->ctlr_dcb.opcode = RSTCFG;		/* command */
23425675Ssam 	ci->ctlr_dcb.intflg = NOINT;
23525675Ssam 	ci->ctlr_dcb.nxtdcb = (fmt_dcb *)0;	/* end of chain */
23625675Ssam 	ci->ctlr_dcb.operrsta = 0;
23725675Ssam 	ci->ctlr_dcb.devselect = (char)slave;
23825675Ssam 	ci->ctlr_dcb.trail.rstrail.ncyl = vdst[type].ncyl;
23925675Ssam 	ci->ctlr_dcb.trail.rstrail.nsurfaces = vdst[type].ntrak;
24025675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
24129921Skarels 		ci->ctlr_dcb.trailcnt = (char)5;
24225675Ssam 		ci->ctlr_dcb.trail.rstrail.nsectors = vdst[type].nsec;
24325675Ssam 		ci->ctlr_dcb.trail.rstrail.slip_sec = vdst[type].nslip;
24429921Skarels 		ci->ctlr_dcb.trail.rstrail.recovery = 0x18f;
24525675Ssam 	} else
24625675Ssam 		ci->ctlr_dcb.trailcnt = (char)2;
24725675Ssam 	ci->ctlr_mdcb.firstdcb = (fmt_dcb *)(PHYS(&ci->ctlr_dcb));
24825675Ssam 	ci->ctlr_mdcb.vddcstat = 0;
24925675Ssam 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(&ci->ctlr_mdcb)), ci->ctlr_type);
25025925Ssam 	if (!vdpoll(ci, addr, 5)) {
25125675Ssam 		printf(" during config\n");
25225675Ssam 		return (0);
25325675Ssam 	}
25425675Ssam 	if (ci->ctlr_dcb.operrsta & HRDERR) {
255*30370Skarels 		if (ci->ctlr_type == SMD_ECTLR &&
256*30370Skarels 		    (addr->cdr_status[slave] & STA_US) == 0) /* not selected */
257*30370Skarels 			return (0);
25825675Ssam 		if ((ci->ctlr_dcb.operrsta & (NOTCYLERR|DRVNRDY)) == 0)
25925675Ssam 			printf("vd%d: drive %d: config error\n", ctlr, slave);
260*30370Skarels 		else if (vdctlr_info[ctlr].ctlr_started == 0)
261*30370Skarels 			return (vdstart_drives(addr, ctlr) &&
262*30370Skarels 			    vdconfigure_drive(addr, ctlr, slave, type));
26325675Ssam 		return (0);
26425675Ssam 	}
26525675Ssam 	return (1);
26624004Ssam }
26724004Ssam 
268*30370Skarels vdstart_drives(addr, ctlr)
26925675Ssam 	cdr *addr;
270*30370Skarels 	register int ctlr;
27124004Ssam {
27225675Ssam 	int error = 0;
27324004Ssam 
274*30370Skarels 	if (vdctlr_info[ctlr].ctlr_started == 0) {
275*30370Skarels 		printf("vd%d: starting drives, wait ... ", ctlr);
276*30370Skarels 		vdctlr_info[ctlr].ctlr_started = 1;
277*30370Skarels 		error = (vdnotrailer(addr, ctlr, 0, VDSTART, 10) & HRDERR);
278*30370Skarels 		DELAY(62000000);
279*30370Skarels 		printf("\n");
28024004Ssam 	}
28125675Ssam 	return (error == 0);
28225675Ssam }
28324004Ssam 
284*30370Skarels vdnotrailer(addr, ctlr, unit, function, t)
28525675Ssam 	register cdr *addr;
286*30370Skarels 	int ctlr, unit, function, t;
28724004Ssam {
28825925Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
28925925Ssam 	fmt_mdcb *mdcb = &ci->ctlr_mdcb;
29025925Ssam 	fmt_dcb *dcb = &ci->ctlr_dcb;
29124004Ssam 
29225675Ssam 	dcb->opcode = function;		/* command */
29324004Ssam 	dcb->intflg = NOINT;
29425675Ssam 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
29525675Ssam 	dcb->operrsta = 0;
29625675Ssam 	dcb->devselect = (char)unit;
29724004Ssam 	dcb->trailcnt = (char)0;
29825675Ssam 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
29924004Ssam 	mdcb->vddcstat = 0;
30025925Ssam 	VDDC_ATTENTION(addr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
301*30370Skarels 	if (!vdpoll(ci, addr, t)) {
30225675Ssam 		printf(" during init\n");
30325675Ssam 		return (DCBCMP|ANYERR|HRDERR|OPABRT);
30424004Ssam 	}
30525675Ssam 	return (dcb->operrsta);
30625675Ssam }
30724004Ssam 
30825675Ssam vdattach(vi)
30925675Ssam 	register struct vba_device *vi;
31025675Ssam {
31125675Ssam 	register unit_tab *ui = &vdunit_info[vi->ui_unit];
31225675Ssam 	register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
31325675Ssam 	register struct buf *cq = &vi->ui_mi->um_tab;
31425675Ssam 	register struct buf *uq = cq->b_forw;
31525675Ssam 	register struct buf *start_queue = uq;
31625675Ssam 	register fs_tab	*fs = &ui->info;
31725675Ssam 
31825675Ssam 	ui->info = vdst[vi->ui_type];
31925675Ssam 	ui->sec_per_blk = DEV_BSIZE / ui->info.secsize;
32025675Ssam 	ui->sec_per_cyl = ui->info.nsec * ui->info.ntrak;
32125675Ssam 	ui->xfer_queue.b_dev = vi->ui_slave;
32225675Ssam 	ci->unit_type[vi->ui_slave] = vi->ui_type;
32325675Ssam 	/* load unit into controller's active unit list */
32425675Ssam 	if (uq == NULL) {
32525675Ssam 		cq->b_forw = &ui->xfer_queue;
32625675Ssam 		ui->xfer_queue.b_forw = &ui->xfer_queue;
32725675Ssam 		ui->xfer_queue.b_back = &ui->xfer_queue;
32825675Ssam 	} else {
32925675Ssam 		while (uq->b_forw != start_queue)
33025675Ssam 			uq = uq->b_forw;
33125675Ssam 		ui->xfer_queue.b_forw = start_queue;
33225675Ssam 		ui->xfer_queue.b_back = uq;
33325675Ssam 		uq->b_forw = &ui->xfer_queue;
33425675Ssam 		start_queue->b_back = &ui->xfer_queue;
33525675Ssam 	}
336*30370Skarels 	printf(": %s <ntrak %d, ncyl %d, nsec %d>",
337*30370Skarels 	    fs->type_name, ui->info.ntrak, ui->info.ncyl, ui->info.nsec);
33824004Ssam 	/*
33925675Ssam 	 * (60 / rpm) / (number of sectors per track * (bytes per sector / 2))
34024004Ssam 	 */
34125675Ssam 	dk_mspw[vi->ui_unit] = 120.0 / (fs->rpm * fs->nsec * fs->secsize);
34224004Ssam }
34324004Ssam 
34425675Ssam /*ARGSUSED*/
34525675Ssam vddgo(um)
34625675Ssam 	struct vba_ctlr *um;
34724004Ssam {
34824004Ssam 
34924004Ssam }
35024004Ssam 
35124004Ssam vdstrategy(bp)
35225675Ssam 	register struct buf *bp;
35324004Ssam {
35425675Ssam 	register int unit = VDUNIT(bp->b_dev);
35525675Ssam 	register struct vba_device *vi = vddinfo[unit];
35625675Ssam 	register par_tab *par;
35725675Ssam 	register unit_tab *ui;
35825675Ssam 	register fs_tab *fs;
35925675Ssam 	register int blks, bn, s;
36024004Ssam 
36129954Skarels 	if (bp->b_bcount == 0 || vi == 0 || vi->ui_alive == 0) {
36229954Skarels 		bp->b_error = ENXIO;
36325675Ssam 		goto bad;
36429954Skarels 	}
36525675Ssam 	ui = &vdunit_info[unit];
36625675Ssam 	fs = &ui->info;
36725675Ssam 	par = &fs->partition[FILSYS(bp->b_dev)];
36825675Ssam 	blks = (bp->b_bcount + DEV_BSIZE-1) >> DEV_BSHIFT;
36929954Skarels 	if ((unsigned) bp->b_blkno + blks > par->par_len) {
37029954Skarels 		if (bp->b_blkno == par->par_len) {
37129954Skarels 			bp->b_resid = bp->b_bcount;
37229954Skarels 			goto done;
37329954Skarels 		}
37425675Ssam 		blks = par->par_len - bp->b_blkno;
37529954Skarels 		if (blks <= 0) {
37629954Skarels 			bp->b_error = EINVAL;
37725675Ssam 			goto bad;
37829954Skarels 		}
37925675Ssam 		bp->b_bcount = blks * DEV_BSIZE;
38025675Ssam 	}
38125675Ssam 	bn = bp->b_blkno + par->par_start;
38225675Ssam 	bn *= ui->sec_per_blk;
38325675Ssam 	bp->b_daddr = (bn / fs->nsec) % fs->ntrak;
38425675Ssam 	bp->b_cylin = bn / ui->sec_per_cyl;
38525675Ssam 	vbasetup(bp, ui->info.secsize);
38625675Ssam 	s = spl7();
38725675Ssam 	if (ui->xfer_queue.av_forw == NULL) {
38825675Ssam 		register ctlr_tab *ci = &vdctlr_info[vi->ui_ctlr];
38925675Ssam 		int slave = vi->ui_slave;
39024004Ssam 
39125675Ssam 		if (bp->b_cylin != ci->cur_cyl[slave] ||
39225675Ssam 		    bp->b_daddr != ci->cur_trk[slave])
39325675Ssam 			ci->off_cylinder |= 1 << slave;
39424004Ssam 	}
39525675Ssam 	bp->b_daddr |= (bn % fs->nsec) << 8;
39625675Ssam 	disksort(&ui->xfer_queue, bp);
39725675Ssam 	if (!vddinfo[unit]->ui_mi->um_tab.b_active++) {
39825675Ssam 		splx(s);
39925675Ssam 		vdstart(vddinfo[unit]->ui_mi);
40025675Ssam 	} else
40125675Ssam 		splx(s);
40224004Ssam 	return;
40325675Ssam bad:
40429954Skarels 	bp->b_flags |= B_ERROR;
40529954Skarels done:
40624004Ssam 	iodone(bp);
40724004Ssam }
40824004Ssam 
40924004Ssam /*
41024004Ssam  * Start up a transfer on a drive.
41124004Ssam  */
41225675Ssam vdstart(ci)
41325675Ssam 	register struct vba_ctlr *ci;
41424004Ssam {
41525675Ssam 	register struct buf *cq = &ci->um_tab;
41625675Ssam 	register struct buf *uq = cq->b_forw;
41724004Ssam 
41825675Ssam 	/* search for next ready unit */
41925675Ssam 	cq->b_forw = cq->b_forw->b_forw;
42025675Ssam 	uq = cq->b_forw;
42125675Ssam 	do {
42225675Ssam 		if (uq->av_forw != NULL) {
42325675Ssam 			cq->b_forw = uq;
42425675Ssam 			vdexecute(ci, uq);
42525675Ssam 			return;
42625675Ssam 		}
42725675Ssam 		uq = uq->b_forw;
42825675Ssam 	} while (uq != cq->b_forw);
42925675Ssam }
43025675Ssam 
43125675Ssam /*
43225675Ssam  * Initiate seeks for all drives off-cylinder.
43325675Ssam  */
43425675Ssam vdload_seeks(ci, uq)
43525675Ssam 	register ctlr_tab *ci;
43625675Ssam 	register struct buf *uq;
43725675Ssam {
43825675Ssam 	register int unit, slave, nseeks;
43925675Ssam 	register fmt_dcb *dcb;
44025675Ssam 	register struct buf *bp;
44125675Ssam 	register struct buf *start_queue = uq;
44225675Ssam 
44325675Ssam 	nseeks = 0;
44425675Ssam 	do {
44525675Ssam 		bp = uq->av_forw;
44625675Ssam 		if (bp != NULL) {
44725675Ssam 			unit = VDUNIT(bp->b_dev);
44825675Ssam 			slave = vddinfo[unit]->ui_slave;
44925675Ssam 			if (ci->off_cylinder & (1 << slave)) {
45025675Ssam 				ci->off_cylinder &= ~(1 << slave);
45125675Ssam 				if (ci->cur_cyl[slave] != bp->b_cylin) {
45225675Ssam 					ci->cur_cyl[slave] = bp->b_cylin;
45325675Ssam 					dk_seek[unit]++;
45425675Ssam 				}
45525675Ssam 				ci->cur_trk[slave] = bp->b_daddr&0xff;
45625675Ssam 				dcb = &ci->seek_dcb[nseeks++];
45725675Ssam 				dcb->opcode = SEEK;
45825675Ssam 				dcb->intflg = NOINT | INT_PBA;
45925675Ssam 				dcb->operrsta = 0;
46025675Ssam 				dcb->devselect = (char)slave;
46125675Ssam 				dcb->trailcnt = (char)1;
46225675Ssam 				dcb->trail.sktrail.skaddr.cylinder =
46325675Ssam 				    bp->b_cylin;
46425675Ssam 				dcb->trail.sktrail.skaddr.track =
46525675Ssam 				    bp->b_daddr & 0xff;
46625675Ssam 				dcb->trail.sktrail.skaddr.sector = 0;
46725675Ssam 			}
46825675Ssam 		}
46925675Ssam 		uq = uq->b_forw;
47025675Ssam 	} while (uq != start_queue && nseeks < 4);
47125675Ssam 	return (nseeks);
47225675Ssam }
47325675Ssam 
47425675Ssam extern	vd_int_timeout();
47525675Ssam /*
47625675Ssam  * Execute the next command on the unit queue uq.
47725675Ssam  */
47825675Ssam vdexecute(controller_info, uq)
47925675Ssam 	register struct vba_ctlr *controller_info;
48025675Ssam 	register struct buf *uq;
48125675Ssam {
48225675Ssam 	register struct	buf *bp = uq->av_forw;
48325675Ssam 	register int ctlr = controller_info->um_ctlr;
48425675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
48525675Ssam 	register int unit = VDUNIT(bp->b_dev);
48625675Ssam 	register int slave = vddinfo[unit]->ui_slave;
48725675Ssam 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
48825675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
48925675Ssam 
49024004Ssam 	/*
49125675Ssam 	 * If there are overlapped seeks to perform, shuffle
49225675Ssam 	 * them to the front of the queue and get them started
49325675Ssam 	 * before any data transfers (to get some parallelism).
49424004Ssam 	 */
49525675Ssam 	if ((ci->off_cylinder & ~(1<<slave)) && ci->overlap_seeks) {
49625675Ssam 		register int i, nseeks;
49725675Ssam 
49825675Ssam 		/* setup seek requests in seek-q */
49925675Ssam 		nseeks = vdload_seeks(ci, uq);
50025675Ssam 		/* place at the front of the master q */
50125675Ssam 		mdcb->firstdcb = (fmt_dcb *)PHYS(&ci->seek_dcb[0]);
50225675Ssam 		/* shuffle any remaining seeks up in the seek-q */
50325675Ssam 		for (i = 1; i < nseeks; i++)
50425675Ssam 			ci->seek_dcb[i-1].nxtdcb =
50525675Ssam 			    (fmt_dcb *)PHYS(&ci->seek_dcb[i]);
50625675Ssam 		ci->seek_dcb[nseeks-1].nxtdcb = (fmt_dcb *)PHYS(dcb);
50725675Ssam 	} else {
50825675Ssam 		if (bp->b_cylin != ci->cur_cyl[slave]) {
50925675Ssam 			ci->cur_cyl[slave] = bp->b_cylin;
51025675Ssam 			dk_seek[unit]++;
51125675Ssam 		}
51225675Ssam 		ci->cur_trk[slave] = bp->b_daddr & 0xff;
51325675Ssam 		ci->off_cylinder = 0;
51425675Ssam 		mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
51524004Ssam 	}
51624004Ssam 	dcb->opcode = (bp->b_flags & B_READ) ? RD : WD;
51725675Ssam 	dcb->intflg = INTDONE;
51825675Ssam 	dcb->nxtdcb = (fmt_dcb *)0;	/* end of chain */
51924004Ssam 	dcb->operrsta = 0;
52025675Ssam 	dcb->devselect = (char)slave;
52125675Ssam 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
52225675Ssam 	dcb->trail.rwtrail.memadr = (char *)
52325675Ssam 	    vbastart(bp, ci->rawbuf, (long *)ci->map, ci->utl);
52425675Ssam 	dcb->trail.rwtrail.wcount = (short)((bp->b_bcount+1) / sizeof (short));
52525675Ssam 	dcb->trail.rwtrail.disk.cylinder = bp->b_cylin;
52625675Ssam 	dcb->trail.rwtrail.disk.track = bp->b_daddr & 0xff;
52725675Ssam 	dcb->trail.rwtrail.disk.sector = bp->b_daddr >> 8;
52825675Ssam 	mdcb->vddcstat = 0;
52925675Ssam    	dk_wds[unit] += bp->b_bcount / 32;
53025675Ssam 	ci->int_expected = 1;
531*30370Skarels 	timeout(vd_int_timeout, (caddr_t)ctlr, 20*hz);
53225675Ssam   	dk_busy |= 1 << unit;
53325675Ssam 	scope_out(1);
53425675Ssam 	VDDC_ATTENTION((cdr *)(vdminfo[ctlr]->um_addr),
53525675Ssam 	    (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
53625675Ssam }
53724004Ssam 
53824004Ssam /*
53925675Ssam  * Watch for lost interrupts.
54025675Ssam  */
54125675Ssam vd_int_timeout(ctlr)
54225675Ssam 	register int ctlr;
54325675Ssam {
54425675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
54525675Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
54624004Ssam 
54725675Ssam 	uncache(&dcb->operrsta);
54829921Skarels 	printf("vd%d: lost interrupt, status %b", ctlr, dcb->operrsta, ERRBITS);
54925675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
55025675Ssam 		uncache(&dcb->err_code);
55125675Ssam 		printf(", error code %x", dcb->err_code);
55224004Ssam 	}
55325675Ssam 	printf("\n");
55425675Ssam 	if ((dcb->operrsta&DCBCMP) == 0) {
55525675Ssam 		VDDC_ABORT((cdr *)(vdminfo[ctlr]->um_addr), ci->ctlr_type);
55625675Ssam 		dcb->operrsta |= DCBUSC | DCBABT | ANYERR | HRDERR | CTLRERR;
55725675Ssam 	}
55825675Ssam 	vdintr(ctlr);
55924004Ssam }
56024004Ssam 
56124004Ssam /*
56224004Ssam  * Handle a disk interrupt.
56324004Ssam  */
56425675Ssam vdintr(ctlr)
56525675Ssam 	register int ctlr;
56624004Ssam {
56725675Ssam 	register ctlr_tab *ci;
56825675Ssam 	register struct buf *cq, *uq, *bp;
56925675Ssam 	register int slave, unit;
57025675Ssam 	register fmt_mdcb  *mdcb;
57125675Ssam 	register fmt_dcb *dcb;
57225675Ssam 	int code, s;
57324004Ssam 
57425675Ssam 	untimeout(vd_int_timeout, (caddr_t)ctlr);
57524004Ssam 	scope_out(2);
57625675Ssam 	ci = &vdctlr_info[ctlr];
57725675Ssam 	if (!ci->int_expected) {
57825675Ssam 		printf("vd%d: stray interrupt\n", ctlr);
57924004Ssam 		return;
58024004Ssam 	}
58125675Ssam 	/*
58225675Ssam 	 * Take first request off controller's queue.
58325675Ssam 	 */
58425675Ssam 	cq = &vdminfo[ctlr]->um_tab;
58525675Ssam 	uq = cq->b_forw;
58625675Ssam 	bp = uq->av_forw;
58724004Ssam 	unit = VDUNIT(bp->b_dev);
58825675Ssam 	dk_busy &= ~(1 << unit);
58925675Ssam 	dk_xfer[unit]++;
59025675Ssam 	ci->int_expected = 0;
59125675Ssam 	/* find associated control blocks */
59225675Ssam 	mdcb = &ci->ctlr_mdcb, uncache(&mdcb->intdcb);
59325675Ssam 	dcb = &ci->ctlr_dcb, uncache(&dcb->operrsta);
59425675Ssam 	if (ci->ctlr_type == SMD_ECTLR)
59525675Ssam 		uncache(&dcb->err_code);
59625675Ssam 	slave = uq->b_dev;
59725675Ssam 	switch (code = vddecode_error(dcb)) {
59824004Ssam 
59925675Ssam 	case CTLR_ERROR:
60025675Ssam 	case DRIVE_ERROR:
60125675Ssam 		if (code == CTLR_ERROR)
60225675Ssam 			vdreset_ctlr((cdr *)vdminfo[ctlr]->um_addr, ctlr);
603*30370Skarels 		else if (reset_drive((cdr *)vdminfo[ctlr]->um_addr,
604*30370Skarels 		    ctlr, slave) == 0)
605*30370Skarels 			vddinfo[unit]->ui_alive = 0;
606*30370Skarels 		/*
607*30370Skarels 		 * Retry transfer once, unless reset failed.
608*30370Skarels 		 */
609*30370Skarels 		if (vddinfo[unit]->ui_alive && cq->b_errcnt++ < 2) {
61025675Ssam 			cq->b_forw = uq->b_back;
61125675Ssam 			vdstart(vdminfo[ctlr]);
61225675Ssam 			return;
61325675Ssam 		}
614*30370Skarels 		vdhard_error(ci, bp, dcb);
61525675Ssam 		break;
61625675Ssam 
61725675Ssam 	case HARD_DATA_ERROR:
61829921Skarels 	case WRITE_PROTECT:
619*30370Skarels 	default:				/* shouldn't happen */
62025675Ssam 		vdhard_error(ci, bp, dcb);
62125675Ssam 		bp->b_resid = 0;
62225675Ssam 		break;
62325675Ssam 
62425675Ssam 	case SOFT_DATA_ERROR:
62525675Ssam 		vdsoft_error(ci, bp, dcb);
62625675Ssam 		/* fall thru... */
62725675Ssam 
628*30370Skarels 	case 0:			/* operation completed */
62925675Ssam 		bp->b_error = 0;
63025675Ssam 		bp->b_resid = 0;
63125675Ssam 		break;
63224004Ssam 	}
63325675Ssam 	vbadone(bp, ci->rawbuf, (long *)ci->map, ci->utl);
63425675Ssam 	/*
63525675Ssam 	 * Take next request on this unit q, or, if none,
63625675Ssam 	 * the next request on the next active unit q.
63725675Ssam 	 */
63825675Ssam 	s = spl7();
63925675Ssam 	uq->av_forw = bp->av_forw;
64025675Ssam 	if (uq->av_back != bp) {
64125675Ssam 		register struct buf *next;
64224004Ssam 
64325675Ssam 		unit = VDUNIT(uq->av_forw->b_dev);
64425675Ssam 		slave = vddinfo[unit]->ui_slave;
64525675Ssam 		next = uq->av_forw;
64625675Ssam 		if (next->b_cylin != ci->cur_cyl[slave] ||
64725675Ssam 		    (next->b_daddr & 0xff) != ci->cur_trk[slave])
64825675Ssam 			ci->off_cylinder |= 1 << slave;
64925675Ssam 	} else
65025675Ssam 		uq->av_back = NULL;
65125675Ssam 	splx(s);
65225675Ssam 	/* reset controller state */
65325675Ssam 	cq->b_errcnt = 0;
65425675Ssam 	cq->b_active--;
65524004Ssam 	scope_out(3);
65625675Ssam 	if (bp->b_flags & B_ERROR)
65725675Ssam 		bp->b_error = EIO;
65824004Ssam 	iodone(bp);
65925675Ssam 	vdstart(vdminfo[ctlr]);
66024004Ssam }
66124004Ssam 
66225675Ssam /*
66325675Ssam  * Convert controller status to internal operation/error code.
66425675Ssam  */
66525675Ssam vddecode_error(dcb)
66625675Ssam 	register fmt_dcb *dcb;
66725675Ssam {
66824004Ssam 
66925675Ssam 	if (dcb->operrsta & HRDERR) {
67029921Skarels 		if (dcb->operrsta & WPTERR)
67129921Skarels 			return (WRITE_PROTECT);
672*30370Skarels 	/* this looks wrong...
67329921Skarels 		if (dcb->operrsta & (HCRCERR | HCMPERR | UCDATERR |
674*30370Skarels 		    DSEEKERR | NOTCYLERR | DRVNRDY | INVDADR))
675*30370Skarels 	*/
676*30370Skarels 		if (dcb->operrsta & (DSEEKERR | NOTCYLERR | DRVNRDY | INVDADR))
67725675Ssam 			return (DRIVE_ERROR);
67825675Ssam 		if (dcb->operrsta & (CTLRERR | OPABRT | INVCMD | DNEMEM))
67925675Ssam 			return (CTLR_ERROR);
68025675Ssam 		return (HARD_DATA_ERROR);
68125675Ssam 	}
68225675Ssam 	if (dcb->operrsta & SFTERR)
68325675Ssam 		return (SOFT_DATA_ERROR);
68425675Ssam 	return (0);
68525675Ssam }
68625675Ssam 
68725675Ssam /*
68825675Ssam  * Report a hard error.
68925675Ssam  */
69025675Ssam vdhard_error(ci, bp, dcb)
69125675Ssam 	ctlr_tab *ci;
69225675Ssam 	register struct buf *bp;
69325675Ssam 	register fmt_dcb *dcb;
69425675Ssam {
69525675Ssam 
69625675Ssam 	bp->b_flags |= B_ERROR;
697*30370Skarels 	/* NEED TO ADJUST b_blkno to failed sector */
698*30370Skarels 	harderr(bp, "dk");
69929921Skarels 	if (dcb->operrsta & WPTERR)
70029921Skarels 		printf("write protected");
70129921Skarels 	else {
702*30370Skarels 		printf("status %x (%b)", dcb->operrsta,
703*30370Skarels 		   dcb->operrsta & ~(DSERLY|DSLATE|TOPLUS|TOMNUS|DCBUSC|DCBCMP),
704*30370Skarels 		   ERRBITS);
70529921Skarels 		if (ci->ctlr_type == SMD_ECTLR)
70629921Skarels 			printf(" ecode %x", dcb->err_code);
70729921Skarels 	}
70825675Ssam 	printf("\n");
70925675Ssam }
71025675Ssam 
71125675Ssam /*
71225675Ssam  * Report a soft error.
71325675Ssam  */
71425675Ssam vdsoft_error(ci, bp, dcb)
71525675Ssam 	ctlr_tab *ci;
71625675Ssam 	register struct buf *bp;
71725675Ssam 	register fmt_dcb *dcb;
71825675Ssam {
719*30370Skarels 	int unit = VDUNIT(bp->b_dev);
720*30370Skarels 	char part = 'a' + FILSYS(bp->b_dev);
72125675Ssam 
722*30370Skarels 	if (dcb->operrsta == (DCBCMP | CPDCRT | SFTERR | ANYERR))
723*30370Skarels 		log(LOG_WARNING, "dk%d%c: soft ecc sn%d\n",
724*30370Skarels 		    unit, part, bp->b_blkno);
725*30370Skarels 	else
726*30370Skarels 		log(LOG_WARNING, "dk%d%c: soft error sn%d status %b ecode %x\n",
727*30370Skarels 		    unit, part, bp->b_blkno, dcb->operrsta, ERRBITS,
728*30370Skarels 		    ci->ctlr_type == SMD_ECTLR ? dcb->err_code : 0);
72925675Ssam }
73025675Ssam 
73125675Ssam /*ARGSUSED*/
73225675Ssam vdopen(dev, flag)
73325675Ssam 	dev_t dev;
73425675Ssam 	int flag;
73525675Ssam {
73625675Ssam 	register unit = VDUNIT(dev);
73725675Ssam 	register struct vba_device *vi = vddinfo[unit];
73825675Ssam 
73925675Ssam 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
74025675Ssam 		return (ENXIO);
741*30370Skarels 	if (vi->ui_alive == 0) {
742*30370Skarels 		if (vdconfigure_drive((cdr *)vdminfo[vi->ui_ctlr]->um_addr,
743*30370Skarels 		    vi->ui_ctlr, vi->ui_slave, vi->ui_type))
744*30370Skarels 			vi->ui_alive = 1;
745*30370Skarels 		else
746*30370Skarels 			return (ENXIO);
747*30370Skarels 	}
74825675Ssam 	if (vdunit_info[unit].info.partition[FILSYS(dev)].par_len == 0)
74925675Ssam 		return (ENXIO);
75025675Ssam 	return (0);
75125675Ssam }
75225675Ssam 
75324004Ssam vdread(dev, uio)
75425675Ssam 	dev_t dev;
75525675Ssam 	struct uio *uio;
75624004Ssam {
75724004Ssam 	register int unit = VDUNIT(dev);
75825675Ssam 	register unit_tab *ui = &vdunit_info[unit];
75924004Ssam 
76029564Ssam 	if (unit >= NDK)
76125675Ssam 		return (ENXIO);
76225675Ssam 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_READ,
76325675Ssam 	    minphys, uio));
76424004Ssam }
76524004Ssam 
76624004Ssam vdwrite(dev, uio)
76725675Ssam 	dev_t dev;
76825675Ssam 	struct uio *uio;
76924004Ssam {
77024004Ssam 	register int unit = VDUNIT(dev);
77125675Ssam 	register unit_tab *ui = &vdunit_info[unit];
77224004Ssam 
77329564Ssam 	if (unit >= NDK)
77425675Ssam 		return (ENXIO);
77525675Ssam 	return (physio(vdstrategy, &ui->raw_q_element, dev, B_WRITE,
77625675Ssam 	    minphys, uio));
77724004Ssam }
77824004Ssam 
77924004Ssam /*
78025675Ssam  * Crash dump.
78124004Ssam  */
78225675Ssam vddump(dev)
78325675Ssam 	dev_t dev;
78424004Ssam {
78525675Ssam 	register int unit = VDUNIT(dev);
78625675Ssam 	register unit_tab *ui = &vdunit_info[unit];
78725675Ssam 	register fs_tab *fs = &ui->info;
78825675Ssam 	register int ctlr = vddinfo[unit]->ui_ctlr;
78925675Ssam 	register struct vba_ctlr *vba_vdctlr_info = vdminfo[ctlr];
79025675Ssam 	register int filsys = FILSYS(dev);
79125675Ssam 	register cdr *addr = (cdr *)(vba_vdctlr_info->um_addr);
79225675Ssam 	register int cur_blk, blkcount, blocks;
79325675Ssam 	caddr_t memaddr;
79424004Ssam 
79525675Ssam 	vdreset_ctlr(addr, ctlr);
79624004Ssam 	blkcount = maxfree - 2;		/* In 1k byte pages */
79725675Ssam 	if (dumplo + blkcount > fs->partition[filsys].par_len) {
79825675Ssam 		blkcount = fs->partition[filsys].par_len - dumplo;
799*30370Skarels 		printf("truncated to %dMB ", blkcount/1024);
80025675Ssam 	}
80125675Ssam 	cur_blk = fs->partition[filsys].par_start + dumplo;
80225675Ssam 	memaddr = 0;
80324004Ssam 	while (blkcount > 0) {
80425675Ssam 		blocks = MIN(blkcount, DUMPSIZE);
80525675Ssam 		if (!vdwrite_block(addr, ctlr, unit, memaddr, cur_blk, blocks))
80625675Ssam 			return (EIO);
80725675Ssam 		blkcount -= blocks;
80825675Ssam 		memaddr += blocks * NBPG;
80925675Ssam 		cur_blk += blocks;
81024004Ssam 	}
81125675Ssam 	return (0);
81224004Ssam }
81324004Ssam 
81425675Ssam /*
81525675Ssam  * Write a block to disk during a crash dump.
81625675Ssam  */
81725675Ssam vdwrite_block(caddr, ctlr, unit, addr, block, blocks)
81825675Ssam 	register cdr *caddr;
81925675Ssam 	register int ctlr, unit;
82025675Ssam 	register caddr_t addr;
82125675Ssam 	register int block, blocks;
82224004Ssam {
82325925Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
82425925Ssam 	register fmt_mdcb *mdcb = &ci->ctlr_mdcb;
82525925Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
82625675Ssam 	register unit_tab *ui = &vdunit_info[unit];
82725675Ssam 	register fs_tab	 *fs = &ui->info;
82824004Ssam 
82925675Ssam 	block *= (int)ui->sec_per_blk;
83025675Ssam 	blocks *= (int)ui->sec_per_blk;
83125675Ssam 	mdcb->firstdcb = (fmt_dcb *)(PHYS(dcb));
83225675Ssam 	dcb->intflg = NOINT;
83325675Ssam 	dcb->opcode = WD;
83425675Ssam 	dcb->operrsta = 0;
83525675Ssam 	dcb->devselect = (char)(vddinfo[unit])->ui_slave;
83625675Ssam 	dcb->trailcnt = (char)(sizeof (trrw) / sizeof (long));
83725675Ssam 	dcb->trail.rwtrail.memadr = addr;
83825675Ssam 	dcb->trail.rwtrail.wcount = (short)
83925675Ssam 	    ((blocks * fs->secsize)/ sizeof (short));
84025675Ssam 	dcb->trail.rwtrail.disk.cylinder = (short)(block / ui->sec_per_cyl);
84125675Ssam 	dcb->trail.rwtrail.disk.track = (char)((block / fs->nsec) % fs->ntrak);
84225675Ssam 	dcb->trail.rwtrail.disk.sector = (char)(block % fs->nsec);
84325925Ssam 	VDDC_ATTENTION(caddr, (fmt_mdcb *)(PHYS(mdcb)), ci->ctlr_type);
84425925Ssam 	if (!vdpoll(ci, caddr, 5)) {
84525675Ssam 		printf(" during dump\n");
84625675Ssam 		return (0);
84725675Ssam 	}
84825675Ssam 	if (dcb->operrsta & HRDERR) {
84929921Skarels 		printf("dk%d: hard error, status=%b\n", unit,
85029921Skarels 		    dcb->operrsta, ERRBITS);
85125675Ssam 		return (0);
85225675Ssam 	}
85325675Ssam 	return (1);
85424004Ssam }
85524004Ssam 
85624004Ssam vdsize(dev)
85725675Ssam 	dev_t dev;
85824004Ssam {
85925675Ssam 	struct vba_device *vi = vddinfo[VDUNIT(dev)];
86024004Ssam 
86125675Ssam 	if (vi == 0 || vi->ui_alive == 0 || vi->ui_type >= nvddrv)
86225675Ssam 		return (-1);
86325675Ssam 	return (vdunit_info[VDUNIT(dev)].info.partition[FILSYS(dev)].par_len);
86424004Ssam }
86524004Ssam 
86625675Ssam /*
86725675Ssam  * Perform a controller reset.
86825675Ssam  */
86925675Ssam vdreset_ctlr(addr, ctlr)
87025675Ssam 	register cdr *addr;
87125675Ssam 	register int ctlr;
87224004Ssam {
87325675Ssam 	register struct buf *cq = &vdminfo[ctlr]->um_tab;
87425675Ssam 	register struct buf *uq = cq->b_forw;
87525675Ssam 	register ctlr_tab *ci = &vdctlr_info[ctlr];
87625675Ssam 
87725675Ssam 	VDDC_RESET(addr, ci->ctlr_type);
87825675Ssam 	ci->ctlr_started = 0;
87925675Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
88025675Ssam 		addr->cdr_csr = 0;
88125675Ssam 		addr->mdcb_tcf = AM_ENPDA;
88225675Ssam 		addr->dcb_tcf = AM_ENPDA;
88325675Ssam 		addr->trail_tcf = AM_ENPDA;
88425675Ssam 		addr->data_tcf = AM_ENPDA;
88525675Ssam 		addr->cdr_ccf = CCF_STS | XMD_32BIT | BSZ_16WRD |
88625675Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
88725675Ssam 	}
88825675Ssam 	if (vdnotrailer(addr, ctlr, 0, INIT, 10) & HRDERR) {
88925675Ssam 		printf("failed to init\n");
890*30370Skarels 		return;
89125675Ssam 	}
89225675Ssam 	if (vdnotrailer(addr, ctlr, 0, DIAG, 10) & HRDERR) {
89325675Ssam 		printf("diagnostic error\n");
894*30370Skarels 		return;
89525675Ssam 	}
89625675Ssam 	/*  reset all units attached to controller */
89725675Ssam 	uq = cq->b_forw;
89825675Ssam 	do {
899*30370Skarels 		(void) reset_drive(addr, ctlr, uq->b_dev);
90025675Ssam 		uq = uq->b_forw;
90125675Ssam 	} while (uq != cq->b_forw);
90225675Ssam }
90324004Ssam 
90425675Ssam /*
90525675Ssam  * Perform a reset on a drive.
90625675Ssam  */
907*30370Skarels reset_drive(addr, ctlr, slave)
908*30370Skarels 	cdr *addr;
909*30370Skarels 	int ctlr, slave;
91025675Ssam {
911*30370Skarels 	int type = vdctlr_info[ctlr].unit_type[slave];
91225675Ssam 
91325675Ssam 	if (type == UNKNOWN)
914*30370Skarels 		return (0);
915*30370Skarels 	if (!vdconfigure_drive(addr, ctlr, slave, type)) {
91625675Ssam 		printf("vd%d: drive %d: couldn't reset\n", ctlr, slave);
917*30370Skarels 		return (0);
918*30370Skarels 	}
919*30370Skarels 	return (1);
92025675Ssam }
92125675Ssam 
92225925Ssam /*
92325925Ssam  * Poll controller until operation completes
92425925Ssam  * or timeout expires.
92525925Ssam  */
92625925Ssam vdpoll(ci, addr, t)
92725925Ssam 	register ctlr_tab *ci;
92825925Ssam 	register cdr *addr;
92925925Ssam 	register int t;
93025925Ssam {
93125925Ssam 	register fmt_dcb *dcb = &ci->ctlr_dcb;
93225925Ssam 
93325925Ssam 	t *= 1000;
934*30370Skarels 	for (;;) {
93525925Ssam 		uncache(&dcb->operrsta);
936*30370Skarels 		if (dcb->operrsta & (DCBCMP|DCBABT))
937*30370Skarels 			break;
93825925Ssam 		if (--t <= 0) {
93925925Ssam 			printf("vd%d: controller timeout", ci-vdctlr_info);
94025925Ssam 			VDDC_ABORT(addr, ci->ctlr_type);
94125925Ssam 			DELAY(30000);
94225925Ssam 			uncache(&dcb->operrsta);
94325925Ssam 			return (0);
94425925Ssam 		}
945*30370Skarels 		DELAY(1000);
94625925Ssam 	}
94725925Ssam 	if (ci->ctlr_type == SMD_ECTLR) {
948*30370Skarels 		for (;;) {
949*30370Skarels 			uncache(&addr->cdr_csr);
950*30370Skarels 			if ((addr->cdr_csr & CS_GO) == 0)
951*30370Skarels 				break;
95225925Ssam 			DELAY(50);
95325925Ssam 		}
95425925Ssam 		DELAY(300);
95525925Ssam 	}
95625925Ssam 	DELAY(200);
95725925Ssam 	uncache(&dcb->operrsta);
95825925Ssam 	return (1);
95925925Ssam }
96025925Ssam 
96125675Ssam #ifdef notdef
96225675Ssam /*
96325675Ssam  * Dump the mdcb and DCB for diagnostic purposes.
96425675Ssam  */
96525675Ssam vdprintdcb(lp)
96625675Ssam 	register long *lp;
96725675Ssam {
96825675Ssam 	register int i, dcb, tc;
96925675Ssam 
97025675Ssam 	for (dcb = 0; lp; lp = (long *)(*lp), dcb++) {
97125675Ssam 		lp = (long *)((long)lp | 0xc0000000);
97225675Ssam 		printf("\nDump of dcb%d@%x:", dcb, lp);
97325675Ssam 		for (i = 0, tc = lp[3] & 0xff; i < tc+7; i++)
97425675Ssam 			printf(" %lx", lp[i]);
97525675Ssam 		printf("\n");
97624004Ssam 	}
97725675Ssam 	DELAY(1750000);
97824004Ssam }
97924004Ssam #endif
98025675Ssam #endif
981