xref: /csrg-svn/sys/tahoe/stand/vd.c (revision 32604)
1*32604Skarels /*	vd.c	7.8	87/11/12	*/
229567Ssam 
325873Ssam /*
430521Ssam  * Stand alone driver for the VDDC/SMDE controller
529567Ssam  */
625873Ssam #include "../machine/mtpr.h"
725873Ssam 
825873Ssam #include "param.h"
925873Ssam #include "inode.h"
1025873Ssam #include "fs.h"
1130823Skarels #include "buf.h"
1230521Ssam #include "disklabel.h"
1330521Ssam #include "saio.h"
1430521Ssam 
1525931Ssam #include "../tahoevba/vdreg.h"
1625931Ssam #include "../tahoevba/vbaparam.h"
1725873Ssam 
1830521Ssam #define	COMPAT_42	1
1925873Ssam 
2030521Ssam #define NVD		4
2130521Ssam #define	NDRIVE		8		/* drives per controller */
2230521Ssam #define VDSLAVE(x)	((x) % NDRIVE)
2330521Ssam #define VDCTLR(x)	((x) / NDRIVE)
2425873Ssam 
2530521Ssam #define	VDADDR(ctlr)	((struct vddevice *)vdaddrs[ctlr])
2630521Ssam long	vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 };
2725873Ssam 
2830521Ssam u_char	vdinit[NVD];			/* controller initialized */
2930521Ssam u_char	vdtype[NVD];			/* controller type */
3030521Ssam u_char	dkconfigured[NVD*NDRIVE];	/* unit configured */
31*32604Skarels u_char	dkflags[NVD][NDRIVE];		/* unit flags */
3225873Ssam 
33*32604Skarels static	struct disklabel dklabel[NVD*NDRIVE];	/* pack label */
34*32604Skarels static	struct mdcb mdcb;
35*32604Skarels static	struct dcb dcb;
36*32604Skarels static	char lbuf[DEV_BSIZE];
3725873Ssam 
3825873Ssam vdopen(io)
3929567Ssam 	register struct iob *io;
4025873Ssam {
4130521Ssam 	register int ctlr = VDCTLR(io->i_unit);
4230521Ssam 	register struct dkinfo *dk;
4330823Skarels 	register struct disklabel *lp, *dlp;
4430521Ssam 	int error;
4525873Ssam 
4629567Ssam 	if (ctlr >= NVD) {
4730521Ssam 		printf("invalid controller number\n");
4830521Ssam 		return (ENXIO);
4925873Ssam 	}
5030521Ssam 	if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit)))
5130521Ssam 		return (error);
5230521Ssam 	lp = &dklabel[io->i_unit];
5330521Ssam 	if (!dkconfigured[io->i_unit]) {
5430521Ssam 		struct iob tio;
5530521Ssam 
5630521Ssam 		/*
5730521Ssam 		 * Read in the pack label.
5830521Ssam 		 */
59*32604Skarels 		lp->d_secsize = 1024;
60*32604Skarels 		lp->d_nsectors = 72;
6130521Ssam 		lp->d_ntracks = 24;
6230521Ssam 		lp->d_ncylinders = 711;
63*32604Skarels 		lp->d_secpercyl = 72*24;
6430521Ssam 		if (!vdreset_drive(io))
6530521Ssam 			return (ENXIO);
6630521Ssam 		tio = *io;
6730521Ssam 		tio.i_bn = LABELSECTOR;
6830521Ssam 		tio.i_ma = lbuf;
6930521Ssam 		tio.i_cc = DEV_BSIZE;
7030521Ssam 		tio.i_flgs |= F_RDDATA;
7130521Ssam 		if (vdstrategy(&tio, READ) != DEV_BSIZE) {
72*32604Skarels 			printf("dk%d: can't read disk label\n", io->i_unit);
7330521Ssam 			return (EIO);
7430521Ssam 		}
7530823Skarels 		dlp = (struct disklabel *)(lbuf + LABELOFFSET);
7630823Skarels 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
7730521Ssam #ifdef COMPAT_42
7830521Ssam 			if (error = vdmaptype(io))
7930521Ssam 				return (error);
8030521Ssam #else
8130823Skarels 			printf("dk%d: unlabeled\n", io->i_unit);
8230521Ssam 			return (ENXIO);
8330521Ssam #endif
84*32604Skarels 		} else {
8530823Skarels 			*lp = *dlp;
86*32604Skarels 			if (!vdreset_drive(io))
87*32604Skarels 				return (ENXIO);
88*32604Skarels 		}
8930521Ssam 		dkconfigured[io->i_unit] = 1;
9025873Ssam 	}
9130521Ssam 	if (io->i_boff < 0 || io->i_boff >= lp->d_npartitions ||
9230521Ssam 	    lp->d_partitions[io->i_boff].p_size == 0) {
9330823Skarels 		printf("dk%d: bad minor\n", io->i_unit);
9430521Ssam 		return (EUNIT);
9525873Ssam 	}
9630521Ssam 	io->i_boff =
9730521Ssam 	    (lp->d_partitions[io->i_boff].p_offset * lp->d_secsize) / DEV_BSIZE;
9830521Ssam 	return (0);
9925873Ssam }
10025873Ssam 
10130521Ssam /*
10230521Ssam  * Reset and initialize the controller.
10330521Ssam  */
10430521Ssam vdreset_ctlr(ctlr, unit)
10530521Ssam 	register int ctlr, unit;
10625873Ssam {
10730521Ssam 	register int i;
10830521Ssam 	register struct vddevice *vdaddr = VDADDR(ctlr);
10925873Ssam 
11030521Ssam 	if (badaddr(vdaddr, 2)) {
11130521Ssam 		printf("vd%d: %x: invalid csr\n", ctlr, vdaddr);
11230521Ssam 		return (ENXIO);
11325873Ssam 	}
11430521Ssam 	/* probe further to find what kind of controller it is */
11530521Ssam 	vdaddr->vdreset = 0xffffffff;
11625873Ssam 	DELAY(1000000);
11730521Ssam 	if (vdaddr->vdreset != 0xffffffff) {
11830521Ssam 		vdtype[ctlr] = VDTYPE_VDDC;
11925873Ssam 		DELAY(1000000);
12029567Ssam 	} else {
12130521Ssam 		vdtype[ctlr] = VDTYPE_SMDE;
12230521Ssam 		vdaddr->vdrstclr = 0;
12325873Ssam 		DELAY(3000000);
12430521Ssam 		vdaddr->vdcsr =  0;
12530521Ssam 		vdaddr->vdtcf_mdcb = AM_ENPDA;
12630521Ssam 		vdaddr->vdtcf_dcb = AM_ENPDA;
12730521Ssam 		vdaddr->vdtcf_trail = AM_ENPDA;
12830521Ssam 		vdaddr->vdtcf_data = AM_ENPDA;
12930521Ssam 		vdaddr->vdccf = CCF_SEN | CCF_DER | CCF_STS |
13030521Ssam 		    XMD_32BIT | BSZ_16WRD |
13130521Ssam 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
13225873Ssam 	}
13330521Ssam 	if (!vdcmd(ctlr, 0, VDOP_INIT, 10) ||
13430521Ssam 	    !vdcmd(ctlr, 0, VDOP_DIAG, 10)) {
13530521Ssam 		vderror(unit, dcb.opcode == VDOP_INIT ? "init" : "diag", &dcb);
13630521Ssam 		return (EIO);
13725873Ssam 	}
13830521Ssam 	vdinit[ctlr] = 1;
13930521Ssam 	for (i = unit = ctlr * NDRIVE; i < unit + NDRIVE; i++)
14030521Ssam 		dkconfigured[i] = 0;
14130521Ssam 	return (0);
14225873Ssam }
14325873Ssam 
14430521Ssam /*
14530521Ssam  * Reset and configure a drive's parameters.
14630521Ssam  */
14730521Ssam vdreset_drive(io)
14829567Ssam 	register struct iob *io;
14925873Ssam {
15030521Ssam 	register int ctlr = VDCTLR(io->i_unit), slave = VDSLAVE(io->i_unit);
151*32604Skarels 	register struct disklabel *lp = &dklabel[io->i_unit];
15230521Ssam 	register struct vddevice *vdaddr = VDADDR(ctlr);
15330521Ssam 	int pass = 0, type = vdtype[ctlr], error;
154*32604Skarels 	int devflags = dkflags[ctlr][slave];		/* starts with 0 */
15525873Ssam 
15630521Ssam again:
15730521Ssam 	dcb.opcode = VDOP_CONFIG;		/* command */
15830521Ssam 	dcb.intflg = DCBINT_NONE;
15930521Ssam 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
16030521Ssam 	dcb.operrsta = 0;
161*32604Skarels 	dcb.devselect = slave | devflags;
16230521Ssam 	dcb.trail.rstrail.ncyl = lp->d_ncylinders;
16330521Ssam 	dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
16430521Ssam 	if (type == VDTYPE_SMDE) {
16530823Skarels 		dcb.trailcnt = sizeof (struct treset) / sizeof (long);
16630521Ssam 		dcb.trail.rstrail.nsectors = lp->d_nsectors;
167*32604Skarels 		dcb.trail.rstrail.slip_sec = lp->d_trackskew;
168*32604Skarels 		dcb.trail.rstrail.recovery = VDRF_NORMAL;
16930521Ssam 	} else
17030521Ssam 		dcb.trailcnt = 2;	/* XXX */
17130521Ssam 	mdcb.mdcb_head = &dcb;
17230521Ssam 	mdcb.mdcb_status = 0;
17330521Ssam 	VDGO(vdaddr, (u_long)&mdcb, type);
17430521Ssam 	if (!vdpoll(vdaddr, &dcb, 10, type)) {
17530521Ssam 		if (pass++ != 0) {
17630521Ssam 			printf(" during drive configuration.\n");
17730521Ssam 			return (0);
17830521Ssam 		}
17930521Ssam 		VDRESET(vdaddr, type);
18030521Ssam 		if (error = vdreset_ctlr(ctlr, io->i_unit))
18130521Ssam 			return (error);
18230521Ssam 		goto again;
18325873Ssam 	}
184*32604Skarels 	if ((dcb.operrsta & VDERR_HARD) == 0) {		/* success */
185*32604Skarels 		dkflags[ctlr][slave] = devflags;
18630521Ssam 		return (1);
187*32604Skarels 	}
188*32604Skarels 	if (devflags == 0) {
189*32604Skarels 		devflags = VD_ESDI;
190*32604Skarels 		goto again;
191*32604Skarels 	}
19230521Ssam 	if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) {
19330521Ssam 		printf("dk%d: nonexistent drive\n", io->i_unit);
19430521Ssam 		return (0);
19525873Ssam 	}
19630521Ssam 	if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) {
19730521Ssam 		vderror(io->i_unit, "config", &dcb);
19830521Ssam 		return (0);
19930521Ssam 	}
200*32604Skarels 	devflags = 0;
20130521Ssam 	if (pass++)			/* give up */
20230521Ssam 		return (0);
20330521Ssam 	/*
20430521Ssam 	 * Try to spin up drive with remote command.
20530521Ssam 	 */
20630521Ssam 	if (!vdcmd(ctlr, 0, VDOP_START, 62)) {
20730521Ssam 		vderror(io->i_unit, "start", &dcb);
20830521Ssam 		return (0);
20930521Ssam 	}
21029984Skarels 	DELAY(62000000);
21130521Ssam 	goto again;
21225873Ssam }
21325873Ssam 
21430521Ssam vdcmd(ctlr, unit, cmd, time)
21530521Ssam 	register int ctlr;
21630521Ssam 	int unit, cmd, time;
21725873Ssam {
21830521Ssam 	register struct vddevice *vdaddr = VDADDR(ctlr);
21925873Ssam 
22030521Ssam 	dcb.opcode = cmd;
22130521Ssam 	dcb.intflg = DCBINT_NONE;
22230521Ssam 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
22325873Ssam 	dcb.operrsta  = 0;
224*32604Skarels 	dcb.devselect = unit | dkflags[ctlr][unit];
22530521Ssam 	dcb.trailcnt = 0;
22630521Ssam 	mdcb.mdcb_head = &dcb;
22730521Ssam 	mdcb.mdcb_status = 0;
22830521Ssam 	VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]);
22930521Ssam 	if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr]))
23030521Ssam 		_stop(" during initialization operation.\n");
23130521Ssam 	return ((dcb.operrsta & VDERR_HARD) == 0);
23225873Ssam }
23325873Ssam 
23430521Ssam vdstrategy(io, cmd)
23529567Ssam 	register struct iob *io;
23630521Ssam 	int cmd;
23725873Ssam {
23830521Ssam 	register struct disklabel *lp;
239*32604Skarels 	int ctlr, cn, tn, sn, slave, retries = 0;
24030521Ssam 	daddr_t bn;
24130521Ssam 	struct vddevice *vdaddr;
24225873Ssam 
24329567Ssam 	if (io->i_cc == 0 || io->i_cc > 65535) {
24429567Ssam 		printf("dk%d: invalid transfer size %d\n", io->i_unit,
24529567Ssam 		    io->i_cc);
24630521Ssam 		io->i_error = EIO;
24730521Ssam 		return (-1);
24829567Ssam 	}
24930521Ssam 	lp = &dklabel[io->i_unit];
25030521Ssam 	bn = io->i_bn * (DEV_BSIZE / lp->d_secsize);
25130521Ssam 	cn = bn / lp->d_secpercyl;
25230521Ssam 	sn = bn % lp->d_secpercyl;
25330521Ssam 	tn = sn / lp->d_nsectors;
25430521Ssam 	sn = sn % lp->d_nsectors;
25530521Ssam 
256*32604Skarels top:
25730521Ssam 	dcb.opcode = (cmd == READ ? VDOP_RD : VDOP_WD);
25830521Ssam 	dcb.intflg = DCBINT_NONE;
25930521Ssam 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
26030521Ssam 	dcb.operrsta  = 0;
261*32604Skarels 	ctlr = VDCTLR(io->i_unit);
262*32604Skarels 	slave = VDSLAVE(io->i_unit);
263*32604Skarels 	dcb.devselect = slave | dkflags[ctlr][slave];
26430823Skarels 	dcb.trailcnt = sizeof (struct trrw) / sizeof (int);
26530823Skarels 	dcb.trail.rwtrail.memadr = (u_long)io->i_ma;
26630521Ssam 	dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short);
26730521Ssam 	dcb.trail.rwtrail.disk.cylinder = cn;
26830521Ssam 	dcb.trail.rwtrail.disk.track = tn;
26930521Ssam 	dcb.trail.rwtrail.disk.sector = sn;
27030521Ssam 	mdcb.mdcb_head = &dcb;
27130521Ssam 	mdcb.mdcb_status = 0;
27230521Ssam 	vdaddr = VDADDR(ctlr);
27330521Ssam 	VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]);
27430521Ssam 	if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr]))
27530521Ssam 		_stop(" during i/o operation.\n");
27630521Ssam 	if (dcb.operrsta & VDERR_HARD) {
277*32604Skarels 		if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 &&
278*32604Skarels 		    vdreset_drive(io))
279*32604Skarels 			goto top;
28030521Ssam 		vderror(io->i_unit, cmd == READ ? "read" : "write", &dcb);
28130312Ssam 		io->i_error = EIO;
28229567Ssam 		return (-1);
28325873Ssam 	}
28425873Ssam 	mtpr(PADC, 0);
28529567Ssam 	return (io->i_cc);
28625873Ssam }
28725873Ssam 
28830521Ssam vderror(unit, cmd, dcb)
28929567Ssam 	int unit;
29030521Ssam 	char *cmd;
29130521Ssam 	struct dcb *dcb;
29225873Ssam {
29329567Ssam 
29430521Ssam 	printf("dk%d: %s error; status %b", unit, cmd,
29530521Ssam 	    dcb->operrsta, VDERRBITS);
29630521Ssam 	if (dcb->err_code)
29730521Ssam 		printf(", code %x", dcb->err_code);
29825873Ssam 	printf("\n");
29925873Ssam }
30025873Ssam 
30125873Ssam /*
30230521Ssam  * Poll controller until operation
30330521Ssam  * completes or timeout expires.
30429567Ssam  */
30530521Ssam vdpoll(vdaddr, dcb, t, type)
30630521Ssam 	register struct vddevice *vdaddr;
30730521Ssam 	register struct dcb *dcb;
30825931Ssam 	register int t, type;
30925931Ssam {
31025931Ssam 
31125931Ssam 	t *= 1000;
31230312Ssam 	for (;;) {
31325931Ssam 		uncache(&dcb->operrsta);
31430521Ssam 		if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT))
31530312Ssam 			break;
31625931Ssam 		if (--t <= 0) {
31725931Ssam 			printf("vd: controller timeout");
31830521Ssam 			VDABORT(vdaddr, type);
31925931Ssam 			DELAY(30000);
32025931Ssam 			uncache(&dcb->operrsta);
32125931Ssam 			return (0);
32225931Ssam 		}
32330312Ssam 		DELAY(1000);
32425931Ssam 	}
32530521Ssam 	if (type == VDTYPE_SMDE) {
32630312Ssam 		for (;;) {
32730521Ssam 			uncache(&vdaddr->vdcsr);
32830521Ssam 			if ((vdaddr->vdcsr & CS_GO) == 0)
32930312Ssam 				break;
33025931Ssam 			DELAY(50);
33125931Ssam 		}
33225931Ssam 		DELAY(300);
33329984Skarels 		uncache(&dcb->err_code);
33425931Ssam 	}
33525931Ssam 	DELAY(200);
33625931Ssam 	uncache(&dcb->operrsta);
33725931Ssam 	return (1);
33825931Ssam }
33930521Ssam 
34030521Ssam #ifdef COMPAT_42
34130521Ssam struct	dkcompat {
34230521Ssam 	int	nsectors;		/* sectors per track */
34330521Ssam 	int	ntracks;		/* tracks per cylinder */
34430521Ssam 	int	ncylinders;		/* cylinders per drive */
345*32604Skarels 	int	secsize;		/* sector size */
34630521Ssam #define	NPART	2
34730521Ssam 	int	poff[NPART];		/* [a+b] for bootstrapping */
34830521Ssam } dkcompat[] = {
349*32604Skarels 	{ 48, 24,  711,  512, 0, 61056 },	/* xsd */
350*32604Skarels 	{ 44, 20,  842,  512, 0, 52800 },	/* eagle */
351*32604Skarels 	{ 64, 10,  823,  512, 0, 38400 },	/* fuji 360 */
352*32604Skarels 	{ 32, 24,  711,  512, 0, 40704 },	/* xfd */
353*32604Skarels 	{ 32, 19,  823,  512, 0, 40128 },	/* smd */
354*32604Skarels 	{ 32, 10,  823,  512, 0, 19200 },	/* fsd */
355*32604Skarels 	{ 18, 15, 1224, 1024, 0, 21600 },	/* mxd */
35630521Ssam };
35730521Ssam #define	NDKCOMPAT	(sizeof (dkcompat) / sizeof (dkcompat[0]))
35830521Ssam 
35930521Ssam /*
36030521Ssam  * Identify and configure drive from above table
36130521Ssam  * by trying to read the last sector until a description
36230521Ssam  * is found for which we're successful.
36330521Ssam  */
36430521Ssam vdmaptype(io)
36530521Ssam 	struct iob *io;
36630521Ssam {
36730521Ssam 	register struct disklabel *lp = &dklabel[io->i_unit];
36830521Ssam 	register struct dkcompat *dp;
369*32604Skarels 	int i, ctlr, slave, type;
37030521Ssam 	struct vddevice *vdaddr;
37130521Ssam 
37230521Ssam 	ctlr = VDCTLR(io->i_unit);
373*32604Skarels 	slave = VDSLAVE(io->i_unit);
37430521Ssam 	vdaddr = VDADDR(ctlr);
37530521Ssam 	type = vdtype[ctlr];
37630521Ssam 	for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) {
37730521Ssam 		if (type == VDTYPE_VDDC && dp->nsectors != 32)
37830521Ssam 			continue;
37930521Ssam 		lp->d_nsectors = dp->nsectors;
38030521Ssam 		lp->d_ntracks = dp->ntracks;
38130521Ssam 		lp->d_ncylinders = dp->ncylinders;
382*32604Skarels 		lp->d_secsize = dp->secsize;
38330521Ssam 		if (!vdreset_drive(io))		/* set drive parameters */
38430521Ssam 			return (EIO);
38530521Ssam 		dcb.opcode = VDOP_RD;
38630521Ssam 		dcb.intflg = DCBINT_NONE;
38730521Ssam 		dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
388*32604Skarels 		dcb.devselect = slave | dkflags[ctlr][slave];
38930521Ssam 		dcb.operrsta = 0;
39030823Skarels 		dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
39130823Skarels 		dcb.trail.rwtrail.memadr = (u_long)lbuf;
392*32604Skarels 		dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short);
39330521Ssam 		dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2;
39430521Ssam 		dcb.trail.rwtrail.disk.track = dp->ntracks - 1;
39530521Ssam 		dcb.trail.rwtrail.disk.sector = dp->nsectors - 1;
39630521Ssam 		mdcb.mdcb_head = &dcb;
39730521Ssam 		mdcb.mdcb_status = 0;
39830521Ssam 		VDGO(vdaddr, (u_long)&mdcb, type);
39930521Ssam 		if (!vdpoll(vdaddr, &dcb, 60, type))
40030521Ssam 			_stop(" during i/o operation.\n");
40130521Ssam 		if (dcb.operrsta & VDERR_HARD)
40230521Ssam 			continue;
40330521Ssam 		/* simulate necessary parts of disk label */
40430521Ssam 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
40530521Ssam 		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
40630521Ssam 		lp->d_npartitions = NPART;
40730521Ssam 		for (i = 0; i < NPART; i++) {
40830521Ssam 			lp->d_partitions[i].p_offset = dp->poff[i];
40930521Ssam 			lp->d_partitions[i].p_size =
41030521Ssam 			    lp->d_secperunit - dp->poff[i];
41130521Ssam 		}
41230521Ssam 		return (0);
41330521Ssam 	}
41430521Ssam 	printf("dk%d: unknown drive type\n", io->i_unit);
41530521Ssam 	return (ENXIO);
41630521Ssam }
41730521Ssam #endif
418