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