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