xref: /original-bsd/sys/tahoe/stand/vd.c (revision 48d2e7c6)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Computer Consoles Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)vd.c	7.18 (Berkeley) 05/04/91
11  */
12 
13 /*
14  * Stand alone driver for the VDDC/SMDE controller
15  */
16 #include "machine/mtpr.h"
17 
18 #include "sys/param.h"
19 #include "sys/time.h"
20 #include "sys/buf.h"
21 #include "sys/disklabel.h"
22 #include "stand/saio.h"
23 
24 #include "../vba/vdreg.h"
25 #include "../vba/vbaparam.h"
26 
27 #define	COMPAT_42	1
28 
29 #define NVD		4		/* controllers */
30 #define	NDRIVE		8		/* drives per controller */
31 
32 #define	VDADDR(ctlr)	((struct vddevice *)vdaddrs[ctlr])
33 long	vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 };
34 
35 u_char	vdinit[NVD];			/* controller initialized */
36 u_char	vdtype[NVD];			/* controller type */
37 u_char	dkconfigured[NVD][NDRIVE];	/* unit configured */
38 u_char	dkflags[NVD][NDRIVE];		/* unit flags */
39 
40 static	struct disklabel dklabel[NVD][NDRIVE];	/* pack label */
41 static	struct mdcb mdcb;
42 static	struct dcb dcb;
43 static	char lbuf[DEV_BSIZE];
44 
45 vdopen(io)
46 	register struct iob *io;
47 {
48 	register int ctlr = io->i_ctlr;
49 	register struct dkinfo *dk;
50 	register struct disklabel *lp, *dlp;
51 	int error;
52 
53 	if ((u_int)io->i_adapt)
54 		return (EADAPT);
55 	if ((u_int)ctlr >= NVD)
56 		return (ECTLR);
57 	if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit)))
58 		return (error);
59 	lp = &dklabel[io->i_ctlr][io->i_unit];
60 	if (!dkconfigured[io->i_ctlr][io->i_unit]) {
61 		struct iob tio;
62 
63 		/*
64 		 * Read in the pack label.
65 		 */
66 		lp->d_secsize = 1024;
67 		lp->d_nsectors = 72;
68 		lp->d_ntracks = 24;
69 		lp->d_ncylinders = 711;
70 		lp->d_secpercyl = 72*24;
71 		if (!vdreset_drive(io))
72 			return (ENXIO);
73 		tio = *io;
74 		tio.i_bn = LABELSECTOR;
75 		tio.i_ma = lbuf;
76 		tio.i_cc = DEV_BSIZE;
77 		tio.i_flgs |= F_RDDATA;
78 		if (vdstrategy(&tio, F_READ) != DEV_BSIZE)
79 			return (ERDLAB);
80 		dlp = (struct disklabel *)(lbuf + LABELOFFSET);
81 		if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
82 #ifdef COMPAT_42
83 		{
84 			printf("dk%d: unlabeled\n", io->i_unit);
85 			if (error = vdmaptype(io))
86 				return (error);
87 		}
88 #else
89 			return (EUNLAB);
90 #endif
91 		else {
92 			*lp = *dlp;
93 			if (!vdreset_drive(io))
94 				return (ENXIO);
95 		}
96 		dkconfigured[io->i_ctlr][io->i_unit] = 1;
97 	}
98 	if (io->i_part < 0 || io->i_part >= lp->d_npartitions ||
99 	    lp->d_partitions[io->i_part].p_size == 0)
100 		return (EPART);
101 	io->i_boff =
102 	    (lp->d_partitions[io->i_part].p_offset * lp->d_secsize) / DEV_BSIZE;
103 	return (0);
104 }
105 
106 /*
107  * Reset and initialize the controller.
108  */
109 vdreset_ctlr(ctlr, unit)
110 	register int ctlr, unit;
111 {
112 	register int i;
113 	register struct vddevice *vdaddr = VDADDR(ctlr);
114 
115 	if (badaddr(vdaddr, 2)) {
116 		printf("vd%d: %x: invalid csr\n", ctlr, vdaddr);
117 		return (ENXIO);
118 	}
119 	/* probe further to find what kind of controller it is */
120 	vdaddr->vdreset = 0xffffffff;
121 	DELAY(1000000);
122 	if (vdaddr->vdreset != 0xffffffff) {
123 		vdtype[ctlr] = VDTYPE_VDDC;
124 		DELAY(1000000);
125 	} else {
126 		vdtype[ctlr] = VDTYPE_SMDE;
127 		vdaddr->vdrstclr = 0;
128 		DELAY(3000000);
129 		vdaddr->vdcsr =  0;
130 		vdaddr->vdtcf_mdcb = AM_ENPDA;
131 		vdaddr->vdtcf_dcb = AM_ENPDA;
132 		vdaddr->vdtcf_trail = AM_ENPDA;
133 		vdaddr->vdtcf_data = AM_ENPDA;
134 		vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS |
135 		    XMD_32BIT | BSZ_16WRD |
136 		    CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
137 	}
138 	if (!vdcmd(ctlr, 0, VDOP_INIT, 10) ||
139 	    !vdcmd(ctlr, 0, VDOP_DIAG, 10)) {
140 		vderror(unit, dcb.opcode == VDOP_INIT ? "init" : "diag", &dcb);
141 		return (EIO);
142 	}
143 	vdinit[ctlr] = 1;
144 	for (i = NDRIVE - 1; i >= 0; i--)
145 		dkconfigured[ctlr][i] = 0;
146 	return (0);
147 }
148 
149 /*
150  * Reset and configure a drive's parameters.
151  */
152 vdreset_drive(io)
153 	register struct iob *io;
154 {
155 	register int ctlr = io->i_ctlr, slave = io->i_unit;
156 	register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit];
157 	register struct vddevice *vdaddr = VDADDR(ctlr);
158 	int pass = 0, type = vdtype[ctlr], error;
159 	int devflags = dkflags[ctlr][slave];		/* starts with 0 */
160 
161 again:
162 	dcb.opcode = VDOP_CONFIG;		/* command */
163 	dcb.intflg = DCBINT_NONE;
164 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
165 	dcb.operrsta = 0;
166 	dcb.devselect = slave | devflags;
167 	dcb.trail.rstrail.ncyl = lp->d_ncylinders;
168 	dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
169 	if (type == VDTYPE_SMDE) {
170 		dcb.trailcnt = sizeof (struct treset) / sizeof (long);
171 		dcb.trail.rstrail.nsectors = lp->d_nsectors;
172 		dcb.trail.rstrail.slip_sec = lp->d_trackskew;
173 		dcb.trail.rstrail.recovery = VDRF_NORMAL;
174 	} else
175 		dcb.trailcnt = 2;	/* XXX */
176 	mdcb.mdcb_head = &dcb;
177 	mdcb.mdcb_status = 0;
178 	VDGO(vdaddr, (u_long)&mdcb, type);
179 	if (!vdpoll(vdaddr, &dcb, 10, type)) {
180 		if (pass++ != 0) {
181 			printf(" during drive configuration.\n");
182 			return (0);
183 		}
184 		VDRESET(vdaddr, type);
185 		if (error = vdreset_ctlr(ctlr, io->i_unit))
186 			return (error);
187 		goto again;
188 	}
189 	if ((dcb.operrsta & VDERR_HARD) == 0) {		/* success */
190 		dkflags[ctlr][slave] = devflags;
191 		return (1);
192 	}
193 	if (devflags == 0) {
194 		devflags = VD_ESDI;
195 		goto again;
196 	}
197 	if (type == VDTYPE_SMDE && (vdaddr->vdstatus[slave] & STA_US) == 0) {
198 		printf("dk%d: nonexistent drive\n", io->i_unit);
199 		return (0);
200 	}
201 	if ((dcb.operrsta & (DCBS_OCYL|DCBS_NRDY)) == 0) {
202 		vderror(io->i_unit, "config", &dcb);
203 		return (0);
204 	}
205 	devflags = 0;
206 	if (pass++)			/* give up */
207 		return (0);
208 	/*
209 	 * Try to spin up drive with remote command.
210 	 */
211 	if (!vdcmd(ctlr, 0, VDOP_START, 62)) {
212 		vderror(io->i_unit, "start", &dcb);
213 		return (0);
214 	}
215 	DELAY(62000000);
216 	goto again;
217 }
218 
219 vdcmd(ctlr, unit, cmd, time)
220 	register int ctlr;
221 	int unit, cmd, time;
222 {
223 	register struct vddevice *vdaddr = VDADDR(ctlr);
224 
225 	dcb.opcode = cmd;
226 	dcb.intflg = DCBINT_NONE;
227 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
228 	dcb.operrsta  = 0;
229 	dcb.devselect = unit | dkflags[ctlr][unit];
230 	dcb.trailcnt = 0;
231 	mdcb.mdcb_head = &dcb;
232 	mdcb.mdcb_status = 0;
233 	VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]);
234 	if (!vdpoll(vdaddr, &dcb, time, vdtype[ctlr]))
235 		_stop(" during initialization operation.\n");
236 	return ((dcb.operrsta & VDERR_HARD) == 0);
237 }
238 
239 vdstrategy(io, cmd)
240 	register struct iob *io;
241 	int cmd;
242 {
243 	register struct disklabel *lp;
244 	int ctlr, cn, tn, sn, slave, retries = 0;
245 	daddr_t bn;
246 	struct vddevice *vdaddr;
247 
248 	if (io->i_cc == 0 || io->i_cc > 65535) {
249 		printf("dk%d: invalid transfer size %d\n", io->i_unit,
250 		    io->i_cc);
251 		io->i_error = EIO;
252 		return (-1);
253 	}
254 	lp = &dklabel[io->i_ctlr][io->i_unit];
255 	bn = io->i_bn * (DEV_BSIZE / lp->d_secsize);
256 	cn = bn / lp->d_secpercyl;
257 	sn = bn % lp->d_secpercyl;
258 	tn = sn / lp->d_nsectors;
259 	sn = sn % lp->d_nsectors;
260 
261 top:
262 	dcb.opcode = (cmd == F_READ ? VDOP_RD : VDOP_WD);
263 	dcb.intflg = DCBINT_NONE;
264 	dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
265 	dcb.operrsta  = 0;
266 	ctlr = io->i_ctlr;
267 	slave = io->i_unit;
268 	dcb.devselect = slave | dkflags[ctlr][slave];
269 	dcb.trailcnt = sizeof (struct trrw) / sizeof (int);
270 	dcb.trail.rwtrail.memadr = (u_long)io->i_ma;
271 	dcb.trail.rwtrail.wcount = (io->i_cc + 1) / sizeof (short);
272 	dcb.trail.rwtrail.disk.cylinder = cn;
273 	dcb.trail.rwtrail.disk.track = tn;
274 	dcb.trail.rwtrail.disk.sector = sn;
275 	mdcb.mdcb_head = &dcb;
276 	mdcb.mdcb_status = 0;
277 	vdaddr = VDADDR(ctlr);
278 	VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]);
279 	if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr]))
280 		_stop(" during i/o operation.\n");
281 	if (dcb.operrsta & VDERR_HARD) {
282 		if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 &&
283 		    vdreset_drive(io))
284 			goto top;
285 		vderror(io->i_unit, cmd == F_READ ? "read" : "write", &dcb);
286 		io->i_error = EIO;
287 		return (-1);
288 	}
289 	mtpr(PADC, 0);
290 	return (io->i_cc);
291 }
292 
293 vderror(unit, cmd, dcb)
294 	int unit;
295 	char *cmd;
296 	struct dcb *dcb;
297 {
298 
299 	printf("dk%d: %s error; status %b", unit, cmd,
300 	    dcb->operrsta, VDERRBITS);
301 	if (dcb->err_code)
302 		printf(", code %x", dcb->err_code);
303 	printf("\n");
304 }
305 
306 /*
307  * Poll controller until operation
308  * completes or timeout expires.
309  */
310 vdpoll(vdaddr, dcb, t, type)
311 	register struct vddevice *vdaddr;
312 	register struct dcb *dcb;
313 	register int t, type;
314 {
315 
316 	t *= 1000;
317 	for (;;) {
318 		uncache(&dcb->operrsta);
319 		if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT))
320 			break;
321 		if (--t <= 0) {
322 			printf("vd: controller timeout");
323 			VDABORT(vdaddr, type);
324 			DELAY(30000);
325 			uncache(&dcb->operrsta);
326 			return (0);
327 		}
328 		DELAY(1000);
329 	}
330 	if (type == VDTYPE_SMDE) {
331 		for (;;) {
332 			uncache(&vdaddr->vdcsr);
333 			if ((vdaddr->vdcsr & CS_GO) == 0)
334 				break;
335 			DELAY(50);
336 		}
337 		DELAY(300);
338 		uncache(&dcb->err_code);
339 	}
340 	DELAY(200);
341 	uncache(&dcb->operrsta);
342 	return (1);
343 }
344 
345 #ifdef COMPAT_42
346 struct	dkcompat {
347 	int	nsectors;		/* sectors per track */
348 	int	ntracks;		/* tracks per cylinder */
349 	int	ncylinders;		/* cylinders per drive */
350 	int	secsize;		/* sector size */
351 #define	NPART	2
352 	int	poff[NPART];		/* [a+b] for bootstrapping */
353 } dkcompat[] = {
354 	{ 64, 20,  842,  512, 0, 61440 },	/* 2361a eagle */
355 	{ 48, 24,  711,  512, 0, 61056 },	/* xsd */
356 	{ 44, 20,  842,  512, 0, 52800 },	/* eagle */
357 	{ 64, 10,  823,  512, 0, 38400 },	/* fuji 360 */
358 	{ 32, 24,  711,  512, 0, 40704 },	/* xfd */
359 	{ 32, 19,  823,  512, 0, 40128 },	/* smd */
360 	{ 32, 10,  823,  512, 0, 19200 },	/* fsd */
361 	{ 18, 15, 1224, 1024, 0, 21600 },	/* mxd */
362 };
363 #define	NDKCOMPAT	(sizeof (dkcompat) / sizeof (dkcompat[0]))
364 
365 /*
366  * Identify and configure drive from above table
367  * by trying to read the last sector until a description
368  * is found for which we're successful.
369  */
370 vdmaptype(io)
371 	struct iob *io;
372 {
373 	register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit];
374 	register struct dkcompat *dp;
375 	int i, ctlr, slave, type;
376 	struct vddevice *vdaddr;
377 
378 	ctlr = io->i_ctlr;
379 	slave = io->i_unit;
380 	vdaddr = VDADDR(ctlr);
381 	type = vdtype[ctlr];
382 	for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) {
383 		if (type == VDTYPE_VDDC && dp->nsectors != 32)
384 			continue;
385 		lp->d_nsectors = dp->nsectors;
386 		lp->d_ntracks = dp->ntracks;
387 		lp->d_ncylinders = dp->ncylinders;
388 		lp->d_secsize = dp->secsize;
389 		if (!vdreset_drive(io))		/* set drive parameters */
390 			return (EIO);
391 		dcb.opcode = VDOP_RD;
392 		dcb.intflg = DCBINT_NONE;
393 		dcb.nxtdcb = (struct dcb *)0;	/* end of chain */
394 		dcb.devselect = slave | dkflags[ctlr][slave];
395 		dcb.operrsta = 0;
396 		dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
397 		dcb.trail.rwtrail.memadr = (u_long)lbuf;
398 		dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short);
399 		dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2;
400 		dcb.trail.rwtrail.disk.track = dp->ntracks - 1;
401 		dcb.trail.rwtrail.disk.sector = dp->nsectors - 1;
402 		mdcb.mdcb_head = &dcb;
403 		mdcb.mdcb_status = 0;
404 		VDGO(vdaddr, (u_long)&mdcb, type);
405 		if (!vdpoll(vdaddr, &dcb, 60, type))
406 			_stop(" during i/o operation.\n");
407 		if (dcb.operrsta & VDERR_HARD)
408 			continue;
409 		/* simulate necessary parts of disk label */
410 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
411 		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
412 		lp->d_npartitions = NPART;
413 		for (i = 0; i < NPART; i++) {
414 			lp->d_partitions[i].p_offset = dp->poff[i];
415 			lp->d_partitions[i].p_size =
416 			    lp->d_secperunit - dp->poff[i];
417 		}
418 		return (0);
419 	}
420 	printf("dk%d: unknown drive type\n", io->i_unit);
421 	return (ENXIO);
422 }
423 #endif
424