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