xref: /csrg-svn/sys/tahoe/stand/vd.c (revision 49096)
135473Sbostic /*
235473Sbostic  * Copyright (c) 1988 The Regents of the University of California.
335473Sbostic  * All rights reserved.
435473Sbostic  *
535473Sbostic  * This code is derived from software contributed to Berkeley by
635473Sbostic  * Computer Consoles Inc.
735473Sbostic  *
844532Sbostic  * %sccs.include.redist.c%
935473Sbostic  *
10*49096Sbostic  *	@(#)vd.c	7.18 (Berkeley) 05/04/91
1135473Sbostic  */
1229567Ssam 
1325873Ssam /*
1430521Ssam  * Stand alone driver for the VDDC/SMDE controller
1529567Ssam  */
1637505Smckusick #include "machine/mtpr.h"
1725873Ssam 
1843457Sroot #include "sys/param.h"
1943457Sroot #include "sys/time.h"
2043457Sroot #include "sys/buf.h"
2143457Sroot #include "sys/disklabel.h"
2245796Sbostic #include "stand/saio.h"
2330521Ssam 
2445796Sbostic #include "../vba/vdreg.h"
2545796Sbostic #include "../vba/vbaparam.h"
2625873Ssam 
2730521Ssam #define	COMPAT_42	1
2825873Ssam 
2934466Sbostic #define NVD		4		/* controllers */
3030521Ssam #define	NDRIVE		8		/* drives per controller */
3125873Ssam 
3230521Ssam #define	VDADDR(ctlr)	((struct vddevice *)vdaddrs[ctlr])
3330521Ssam long	vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 };
3425873Ssam 
3530521Ssam u_char	vdinit[NVD];			/* controller initialized */
3630521Ssam u_char	vdtype[NVD];			/* controller type */
3734466Sbostic u_char	dkconfigured[NVD][NDRIVE];	/* unit configured */
3832604Skarels u_char	dkflags[NVD][NDRIVE];		/* unit flags */
3925873Ssam 
4034466Sbostic static	struct disklabel dklabel[NVD][NDRIVE];	/* pack label */
4132604Skarels static	struct mdcb mdcb;
4232604Skarels static	struct dcb dcb;
4332604Skarels static	char lbuf[DEV_BSIZE];
4425873Ssam 
vdopen(io)4525873Ssam vdopen(io)
4629567Ssam 	register struct iob *io;
4725873Ssam {
4834466Sbostic 	register int ctlr = io->i_ctlr;
4930521Ssam 	register struct dkinfo *dk;
5030823Skarels 	register struct disklabel *lp, *dlp;
5130521Ssam 	int error;
5225873Ssam 
5334466Sbostic 	if ((u_int)io->i_adapt)
5434466Sbostic 		return (EADAPT);
5534466Sbostic 	if ((u_int)ctlr >= NVD)
5634466Sbostic 		return (ECTLR);
5730521Ssam 	if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit)))
5830521Ssam 		return (error);
5934466Sbostic 	lp = &dklabel[io->i_ctlr][io->i_unit];
6034466Sbostic 	if (!dkconfigured[io->i_ctlr][io->i_unit]) {
6130521Ssam 		struct iob tio;
6230521Ssam 
6330521Ssam 		/*
6430521Ssam 		 * Read in the pack label.
6530521Ssam 		 */
6632604Skarels 		lp->d_secsize = 1024;
6732604Skarels 		lp->d_nsectors = 72;
6830521Ssam 		lp->d_ntracks = 24;
6930521Ssam 		lp->d_ncylinders = 711;
7032604Skarels 		lp->d_secpercyl = 72*24;
7130521Ssam 		if (!vdreset_drive(io))
7230521Ssam 			return (ENXIO);
7330521Ssam 		tio = *io;
7430521Ssam 		tio.i_bn = LABELSECTOR;
7530521Ssam 		tio.i_ma = lbuf;
7630521Ssam 		tio.i_cc = DEV_BSIZE;
7730521Ssam 		tio.i_flgs |= F_RDDATA;
78*49096Sbostic 		if (vdstrategy(&tio, F_READ) != DEV_BSIZE)
7934466Sbostic 			return (ERDLAB);
8030823Skarels 		dlp = (struct disklabel *)(lbuf + LABELOFFSET);
8134466Sbostic 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
8230521Ssam #ifdef COMPAT_42
8334466Sbostic 		{
8434466Sbostic 			printf("dk%d: unlabeled\n", io->i_unit);
8530521Ssam 			if (error = vdmaptype(io))
8630521Ssam 				return (error);
8734466Sbostic 		}
8830521Ssam #else
8934466Sbostic 			return (EUNLAB);
9030521Ssam #endif
9134466Sbostic 		else {
9230823Skarels 			*lp = *dlp;
9332604Skarels 			if (!vdreset_drive(io))
9432604Skarels 				return (ENXIO);
9532604Skarels 		}
9634466Sbostic 		dkconfigured[io->i_ctlr][io->i_unit] = 1;
9725873Ssam 	}
9834466Sbostic 	if (io->i_part < 0 || io->i_part >= lp->d_npartitions ||
9934466Sbostic 	    lp->d_partitions[io->i_part].p_size == 0)
10034466Sbostic 		return (EPART);
10130521Ssam 	io->i_boff =
10234466Sbostic 	    (lp->d_partitions[io->i_part].p_offset * lp->d_secsize) / DEV_BSIZE;
10330521Ssam 	return (0);
10425873Ssam }
10525873Ssam 
10630521Ssam /*
10730521Ssam  * Reset and initialize the controller.
10830521Ssam  */
vdreset_ctlr(ctlr,unit)10930521Ssam vdreset_ctlr(ctlr, unit)
11030521Ssam 	register int ctlr, unit;
11125873Ssam {
11230521Ssam 	register int i;
11330521Ssam 	register struct vddevice *vdaddr = VDADDR(ctlr);
11425873Ssam 
11530521Ssam 	if (badaddr(vdaddr, 2)) {
11630521Ssam 		printf("vd%d: %x: invalid csr\n", ctlr, vdaddr);
11730521Ssam 		return (ENXIO);
11825873Ssam 	}
11930521Ssam 	/* probe further to find what kind of controller it is */
12030521Ssam 	vdaddr->vdreset = 0xffffffff;
12125873Ssam 	DELAY(1000000);
12230521Ssam 	if (vdaddr->vdreset != 0xffffffff) {
12330521Ssam 		vdtype[ctlr] = VDTYPE_VDDC;
12425873Ssam 		DELAY(1000000);
12529567Ssam 	} else {
12630521Ssam 		vdtype[ctlr] = VDTYPE_SMDE;
12730521Ssam 		vdaddr->vdrstclr = 0;
12825873Ssam 		DELAY(3000000);
12930521Ssam 		vdaddr->vdcsr =  0;
13030521Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
13130521Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
13230521Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
13330521Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
13435711Sbostic 		vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS |
13530521Ssam 		    XMD_32BIT | BSZ_16WRD |
13630521Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
13725873Ssam 	}
13830521Ssam 	if (!vdcmd(ctlr, 0, VDOP_INIT, 10) ||
13930521Ssam 	    !vdcmd(ctlr, 0, VDOP_DIAG, 10)) {
14030521Ssam 		vderror(unit, dcb.opcode == VDOP_INIT ? "init" : "diag", &dcb);
14130521Ssam 		return (EIO);
14225873Ssam 	}
14330521Ssam 	vdinit[ctlr] = 1;
14434466Sbostic 	for (i = NDRIVE - 1; i >= 0; i--)
14534466Sbostic 		dkconfigured[ctlr][i] = 0;
14630521Ssam 	return (0);
14725873Ssam }
14825873Ssam 
14930521Ssam /*
15030521Ssam  * Reset and configure a drive's parameters.
15130521Ssam  */
vdreset_drive(io)15230521Ssam vdreset_drive(io)
15329567Ssam 	register struct iob *io;
15425873Ssam {
15534466Sbostic 	register int ctlr = io->i_ctlr, slave = io->i_unit;
15634466Sbostic 	register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit];
15730521Ssam 	register struct vddevice *vdaddr = VDADDR(ctlr);
15830521Ssam 	int pass = 0, type = vdtype[ctlr], error;
15932604Skarels 	int devflags = dkflags[ctlr][slave];		/* starts with 0 */
16025873Ssam 
16130521Ssam again:
16230521Ssam 	dcb.opcode = VDOP_CONFIG;		/* command */
16330521Ssam 	dcb.intflg = DCBINT_NONE;
16430521Ssam 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
16530521Ssam 	dcb.operrsta = 0;
16632604Skarels 	dcb.devselect = slave | devflags;
16730521Ssam 	dcb.trail.rstrail.ncyl = lp->d_ncylinders;
16830521Ssam 	dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
16930521Ssam 	if (type == VDTYPE_SMDE) {
17030823Skarels 		dcb.trailcnt = sizeof (struct treset) / sizeof (long);
17130521Ssam 		dcb.trail.rstrail.nsectors = lp->d_nsectors;
17232604Skarels 		dcb.trail.rstrail.slip_sec = lp->d_trackskew;
17332604Skarels 		dcb.trail.rstrail.recovery = VDRF_NORMAL;
17430521Ssam 	} else
17530521Ssam 		dcb.trailcnt = 2;	/* XXX */
17630521Ssam 	mdcb.mdcb_head = &dcb;
17730521Ssam 	mdcb.mdcb_status = 0;
17830521Ssam 	VDGO(vdaddr, (u_long)&mdcb, type);
17930521Ssam 	if (!vdpoll(vdaddr, &dcb, 10, type)) {
18030521Ssam 		if (pass++ != 0) {
18130521Ssam 			printf(" during drive configuration.\n");
18230521Ssam 			return (0);
18330521Ssam 		}
18430521Ssam 		VDRESET(vdaddr, type);
18530521Ssam 		if (error = vdreset_ctlr(ctlr, io->i_unit))
18630521Ssam 			return (error);
18730521Ssam 		goto again;
18825873Ssam 	}
18932604Skarels 	if ((dcb.operrsta & VDERR_HARD) == 0) {		/* success */
19032604Skarels 		dkflags[ctlr][slave] = devflags;
19130521Ssam 		return (1);
19232604Skarels 	}
19332604Skarels 	if (devflags == 0) {
19432604Skarels 		devflags = VD_ESDI;
19532604Skarels 		goto again;
19632604Skarels 	}
19730521Ssam 	if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) {
19830521Ssam 		printf("dk%d: nonexistent drive\n", io->i_unit);
19930521Ssam 		return (0);
20025873Ssam 	}
20130521Ssam 	if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) {
20230521Ssam 		vderror(io->i_unit, "config", &dcb);
20330521Ssam 		return (0);
20430521Ssam 	}
20532604Skarels 	devflags = 0;
20630521Ssam 	if (pass++)			/* give up */
20730521Ssam 		return (0);
20830521Ssam 	/*
20930521Ssam 	 * Try to spin up drive with remote command.
21030521Ssam 	 */
21130521Ssam 	if (!vdcmd(ctlr, 0, VDOP_START, 62)) {
21230521Ssam 		vderror(io->i_unit, "start", &dcb);
21330521Ssam 		return (0);
21430521Ssam 	}
21529984Skarels 	DELAY(62000000);
21630521Ssam 	goto again;
21725873Ssam }
21825873Ssam 
vdcmd(ctlr,unit,cmd,time)21930521Ssam vdcmd(ctlr, unit, cmd, time)
22030521Ssam 	register int ctlr;
22130521Ssam 	int unit, cmd, time;
22225873Ssam {
22330521Ssam 	register struct vddevice *vdaddr = VDADDR(ctlr);
22425873Ssam 
22530521Ssam 	dcb.opcode = cmd;
22630521Ssam 	dcb.intflg = DCBINT_NONE;
22730521Ssam 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
22825873Ssam 	dcb.operrsta  = 0;
22932604Skarels 	dcb.devselect = unit | dkflags[ctlr][unit];
23030521Ssam 	dcb.trailcnt = 0;
23130521Ssam 	mdcb.mdcb_head = &dcb;
23230521Ssam 	mdcb.mdcb_status = 0;
23330521Ssam 	VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]);
23430521Ssam 	if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr]))
23530521Ssam 		_stop(" during initialization operation.\n");
23630521Ssam 	return ((dcb.operrsta & VDERR_HARD) == 0);
23725873Ssam }
23825873Ssam 
vdstrategy(io,cmd)23930521Ssam vdstrategy(io, cmd)
24029567Ssam 	register struct iob *io;
24130521Ssam 	int cmd;
24225873Ssam {
24330521Ssam 	register struct disklabel *lp;
24432604Skarels 	int ctlr, cn, tn, sn, slave, retries = 0;
24530521Ssam 	daddr_t bn;
24630521Ssam 	struct vddevice *vdaddr;
24725873Ssam 
24829567Ssam 	if (io->i_cc == 0 || io->i_cc > 65535) {
24929567Ssam 		printf("dk%d: invalid transfer size %d\n", io->i_unit,
25029567Ssam 		    io->i_cc);
25130521Ssam 		io->i_error = EIO;
25230521Ssam 		return (-1);
25329567Ssam 	}
25434466Sbostic 	lp = &dklabel[io->i_ctlr][io->i_unit];
25530521Ssam 	bn = io->i_bn * (DEV_BSIZE / lp->d_secsize);
25630521Ssam 	cn = bn / lp->d_secpercyl;
25730521Ssam 	sn = bn % lp->d_secpercyl;
25830521Ssam 	tn = sn / lp->d_nsectors;
25930521Ssam 	sn = sn % lp->d_nsectors;
26030521Ssam 
26132604Skarels top:
262*49096Sbostic 	dcb.opcode = (cmd == F_READ ? VDOP_RD : VDOP_WD);
26330521Ssam 	dcb.intflg = DCBINT_NONE;
26430521Ssam 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
26530521Ssam 	dcb.operrsta  = 0;
26634466Sbostic 	ctlr = io->i_ctlr;
26734466Sbostic 	slave = io->i_unit;
26832604Skarels 	dcb.devselect = slave | dkflags[ctlr][slave];
26930823Skarels 	dcb.trailcnt = sizeof (struct trrw) / sizeof (int);
27030823Skarels 	dcb.trail.rwtrail.memadr = (u_long)io->i_ma;
27130521Ssam 	dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short);
27230521Ssam 	dcb.trail.rwtrail.disk.cylinder = cn;
27330521Ssam 	dcb.trail.rwtrail.disk.track = tn;
27430521Ssam 	dcb.trail.rwtrail.disk.sector = sn;
27530521Ssam 	mdcb.mdcb_head = &dcb;
27630521Ssam 	mdcb.mdcb_status = 0;
27730521Ssam 	vdaddr = VDADDR(ctlr);
27830521Ssam 	VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]);
27930521Ssam 	if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr]))
28030521Ssam 		_stop(" during i/o operation.\n");
28130521Ssam 	if (dcb.operrsta & VDERR_HARD) {
28232604Skarels 		if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 &&
28332604Skarels 		    vdreset_drive(io))
28432604Skarels 			goto top;
285*49096Sbostic 		vderror(io->i_unit, cmd == F_READ ? "read" : "write", &dcb);
28630312Ssam 		io->i_error = EIO;
28729567Ssam 		return (-1);
28825873Ssam 	}
28925873Ssam 	mtpr(PADC, 0);
29029567Ssam 	return (io->i_cc);
29125873Ssam }
29225873Ssam 
vderror(unit,cmd,dcb)29330521Ssam vderror(unit, cmd, dcb)
29429567Ssam 	int unit;
29530521Ssam 	char *cmd;
29630521Ssam 	struct dcb *dcb;
29725873Ssam {
29829567Ssam 
29930521Ssam 	printf("dk%d: %s error; status %b", unit, cmd,
30030521Ssam 	    dcb->operrsta, VDERRBITS);
30130521Ssam 	if (dcb->err_code)
30230521Ssam 		printf(", code %x", dcb->err_code);
30325873Ssam 	printf("\n");
30425873Ssam }
30525873Ssam 
30625873Ssam /*
30730521Ssam  * Poll controller until operation
30830521Ssam  * completes or timeout expires.
30929567Ssam  */
vdpoll(vdaddr,dcb,t,type)31030521Ssam vdpoll(vdaddr, dcb, t, type)
31130521Ssam 	register struct vddevice *vdaddr;
31230521Ssam 	register struct dcb *dcb;
31325931Ssam 	register int t, type;
31425931Ssam {
31525931Ssam 
31625931Ssam 	t *= 1000;
31730312Ssam 	for (;;) {
31825931Ssam 		uncache(&dcb->operrsta);
31930521Ssam 		if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT))
32030312Ssam 			break;
32125931Ssam 		if (--t <= 0) {
32225931Ssam 			printf("vd: controller timeout");
32330521Ssam 			VDABORT(vdaddr, type);
32425931Ssam 			DELAY(30000);
32525931Ssam 			uncache(&dcb->operrsta);
32625931Ssam 			return (0);
32725931Ssam 		}
32830312Ssam 		DELAY(1000);
32925931Ssam 	}
33030521Ssam 	if (type == VDTYPE_SMDE) {
33130312Ssam 		for (;;) {
33230521Ssam 			uncache(&vdaddr->vdcsr);
33330521Ssam 			if ((vdaddr->vdcsr & CS_GO) == 0)
33430312Ssam 				break;
33525931Ssam 			DELAY(50);
33625931Ssam 		}
33725931Ssam 		DELAY(300);
33829984Skarels 		uncache(&dcb->err_code);
33925931Ssam 	}
34025931Ssam 	DELAY(200);
34125931Ssam 	uncache(&dcb->operrsta);
34225931Ssam 	return (1);
34325931Ssam }
34430521Ssam 
34530521Ssam #ifdef COMPAT_42
34630521Ssam struct	dkcompat {
34730521Ssam 	int	nsectors;		/* sectors per track */
34830521Ssam 	int	ntracks;		/* tracks per cylinder */
34930521Ssam 	int	ncylinders;		/* cylinders per drive */
35032604Skarels 	int	secsize;		/* sector size */
35130521Ssam #define	NPART	2
35230521Ssam 	int	poff[NPART];		/* [a+b] for bootstrapping */
35330521Ssam } dkcompat[] = {
35434738Sbostic 	{ 64, 20,  842,  512, 0, 61440 },	/* 2361a eagle */
35532604Skarels 	{ 48, 24,  711,  512, 0, 61056 },	/* xsd */
35632604Skarels 	{ 44, 20,  842,  512, 0, 52800 },	/* eagle */
35732604Skarels 	{ 64, 10,  823,  512, 0, 38400 },	/* fuji 360 */
35832604Skarels 	{ 32, 24,  711,  512, 0, 40704 },	/* xfd */
35932604Skarels 	{ 32, 19,  823,  512, 0, 40128 },	/* smd */
36032604Skarels 	{ 32, 10,  823,  512, 0, 19200 },	/* fsd */
36132604Skarels 	{ 18, 15, 1224, 1024, 0, 21600 },	/* mxd */
36230521Ssam };
36330521Ssam #define	NDKCOMPAT	(sizeof (dkcompat) / sizeof (dkcompat[0]))
36430521Ssam 
36530521Ssam /*
36630521Ssam  * Identify and configure drive from above table
36730521Ssam  * by trying to read the last sector until a description
36830521Ssam  * is found for which we're successful.
36930521Ssam  */
37030521Ssam vdmaptype(io)
37130521Ssam 	struct iob *io;
37230521Ssam {
37334466Sbostic 	register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit];
37430521Ssam 	register struct dkcompat *dp;
37532604Skarels 	int i, ctlr, slave, type;
37630521Ssam 	struct vddevice *vdaddr;
37730521Ssam 
37834466Sbostic 	ctlr = io->i_ctlr;
37934466Sbostic 	slave = io->i_unit;
38030521Ssam 	vdaddr = VDADDR(ctlr);
38130521Ssam 	type = vdtype[ctlr];
38230521Ssam 	for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) {
38330521Ssam 		if (type == VDTYPE_VDDC && dp->nsectors != 32)
38430521Ssam 			continue;
38530521Ssam 		lp->d_nsectors = dp->nsectors;
38630521Ssam 		lp->d_ntracks = dp->ntracks;
38730521Ssam 		lp->d_ncylinders = dp->ncylinders;
38832604Skarels 		lp->d_secsize = dp->secsize;
38930521Ssam 		if (!vdreset_drive(io))		/* set drive parameters */
39030521Ssam 			return (EIO);
39130521Ssam 		dcb.opcode = VDOP_RD;
39230521Ssam 		dcb.intflg = DCBINT_NONE;
39330521Ssam 		dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
39432604Skarels 		dcb.devselect = slave | dkflags[ctlr][slave];
39530521Ssam 		dcb.operrsta = 0;
39630823Skarels 		dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
39730823Skarels 		dcb.trail.rwtrail.memadr = (u_long)lbuf;
39832604Skarels 		dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short);
39930521Ssam 		dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2;
40030521Ssam 		dcb.trail.rwtrail.disk.track = dp->ntracks - 1;
40130521Ssam 		dcb.trail.rwtrail.disk.sector = dp->nsectors - 1;
40230521Ssam 		mdcb.mdcb_head = &dcb;
40330521Ssam 		mdcb.mdcb_status = 0;
40430521Ssam 		VDGO(vdaddr, (u_long)&mdcb, type);
40530521Ssam 		if (!vdpoll(vdaddr, &dcb, 60, type))
40630521Ssam 			_stop(" during i/o operation.\n");
40730521Ssam 		if (dcb.operrsta & VDERR_HARD)
40830521Ssam 			continue;
40930521Ssam 		/* simulate necessary parts of disk label */
41030521Ssam 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
41130521Ssam 		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
41230521Ssam 		lp->d_npartitions = NPART;
41330521Ssam 		for (i = 0; i < NPART; i++) {
41430521Ssam 			lp->d_partitions[i].p_offset = dp->poff[i];
41530521Ssam 			lp->d_partitions[i].p_size =
41630521Ssam 			    lp->d_secperunit - dp->poff[i];
41730521Ssam 		}
41830521Ssam 		return (0);
41930521Ssam 	}
42030521Ssam 	printf("dk%d: unknown drive type\n", io->i_unit);
42130521Ssam 	return (ENXIO);
42230521Ssam }
42330521Ssam #endif
424