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