add mpcc support; From: muller%sdcc7@ucsd.edu (Keith Muller)
[unix-history] / usr / src / sys / tahoe / stand / vd.c
CommitLineData
cb69d88e 1/* vd.c 7.9 88/05/24 */
4006c5e1 2
39b72d60 3/*
bff99b3e 4 * Stand alone driver for the VDDC/SMDE controller
4006c5e1 5 */
39b72d60
SL
6#include "../machine/mtpr.h"
7
8#include "param.h"
9#include "inode.h"
10#include "fs.h"
bdfd2fb7 11#include "buf.h"
bff99b3e
SL
12#include "disklabel.h"
13#include "saio.h"
14
1a9cb196 15#include "../tahoevba/vdreg.h"
1a9cb196 16#include "../tahoevba/vbaparam.h"
39b72d60 17
bff99b3e 18#define COMPAT_42 1
39b72d60 19
cb69d88e 20#define NVD 4 /* controllers */
bff99b3e 21#define NDRIVE 8 /* drives per controller */
39b72d60 22
bff99b3e
SL
23#define VDADDR(ctlr) ((struct vddevice *)vdaddrs[ctlr])
24long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 };
39b72d60 25
bff99b3e
SL
26u_char vdinit[NVD]; /* controller initialized */
27u_char vdtype[NVD]; /* controller type */
cb69d88e 28u_char dkconfigured[NVD][NDRIVE]; /* unit configured */
7d68510b 29u_char dkflags[NVD][NDRIVE]; /* unit flags */
39b72d60 30
cb69d88e 31static struct disklabel dklabel[NVD][NDRIVE]; /* pack label */
7d68510b
MK
32static struct mdcb mdcb;
33static struct dcb dcb;
34static char lbuf[DEV_BSIZE];
39b72d60
SL
35
36vdopen(io)
4006c5e1 37 register struct iob *io;
39b72d60 38{
cb69d88e 39 register int ctlr = io->i_ctlr;
bff99b3e 40 register struct dkinfo *dk;
bdfd2fb7 41 register struct disklabel *lp, *dlp;
bff99b3e 42 int error;
39b72d60 43
cb69d88e
KB
44 if ((u_int)io->i_adapt)
45 return (EADAPT);
46 if ((u_int)ctlr >= NVD)
47 return (ECTLR);
bff99b3e
SL
48 if (!vdinit[ctlr] && (error = vdreset_ctlr(ctlr, io->i_unit)))
49 return (error);
cb69d88e
KB
50 lp = &dklabel[io->i_ctlr][io->i_unit];
51 if (!dkconfigured[io->i_ctlr][io->i_unit]) {
bff99b3e
SL
52 struct iob tio;
53
54 /*
55 * Read in the pack label.
56 */
7d68510b
MK
57 lp->d_secsize = 1024;
58 lp->d_nsectors = 72;
bff99b3e
SL
59 lp->d_ntracks = 24;
60 lp->d_ncylinders = 711;
7d68510b 61 lp->d_secpercyl = 72*24;
bff99b3e
SL
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;
cb69d88e
KB
69 if (vdstrategy(&tio, READ) != DEV_BSIZE)
70 return (ERDLAB);
bdfd2fb7 71 dlp = (struct disklabel *)(lbuf + LABELOFFSET);
cb69d88e 72 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC)
bff99b3e 73#ifdef COMPAT_42
cb69d88e
KB
74 {
75 printf("dk%d: unlabeled\n", io->i_unit);
bff99b3e
SL
76 if (error = vdmaptype(io))
77 return (error);
cb69d88e 78 }
bff99b3e 79#else
cb69d88e 80 return (EUNLAB);
bff99b3e 81#endif
cb69d88e 82 else {
bdfd2fb7 83 *lp = *dlp;
7d68510b
MK
84 if (!vdreset_drive(io))
85 return (ENXIO);
86 }
cb69d88e 87 dkconfigured[io->i_ctlr][io->i_unit] = 1;
39b72d60 88 }
cb69d88e
KB
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);
bff99b3e 92 io->i_boff =
cb69d88e 93 (lp->d_partitions[io->i_part].p_offset * lp->d_secsize) / DEV_BSIZE;
bff99b3e 94 return (0);
39b72d60
SL
95}
96
bff99b3e
SL
97/*
98 * Reset and initialize the controller.
99 */
100vdreset_ctlr(ctlr, unit)
101 register int ctlr, unit;
39b72d60 102{
bff99b3e
SL
103 register int i;
104 register struct vddevice *vdaddr = VDADDR(ctlr);
39b72d60 105
bff99b3e
SL
106 if (badaddr(vdaddr, 2)) {
107 printf("vd%d: %x: invalid csr\n", ctlr, vdaddr);
108 return (ENXIO);
39b72d60 109 }
bff99b3e
SL
110 /* probe further to find what kind of controller it is */
111 vdaddr->vdreset = 0xffffffff;
39b72d60 112 DELAY(1000000);
bff99b3e
SL
113 if (vdaddr->vdreset != 0xffffffff) {
114 vdtype[ctlr] = VDTYPE_VDDC;
39b72d60 115 DELAY(1000000);
4006c5e1 116 } else {
bff99b3e
SL
117 vdtype[ctlr] = VDTYPE_SMDE;
118 vdaddr->vdrstclr = 0;
39b72d60 119 DELAY(3000000);
bff99b3e
SL
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;
39b72d60 128 }
bff99b3e
SL
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);
39b72d60 133 }
bff99b3e 134 vdinit[ctlr] = 1;
cb69d88e
KB
135 for (i = NDRIVE - 1; i >= 0; i--)
136 dkconfigured[ctlr][i] = 0;
bff99b3e 137 return (0);
39b72d60
SL
138}
139
bff99b3e
SL
140/*
141 * Reset and configure a drive's parameters.
142 */
143vdreset_drive(io)
4006c5e1 144 register struct iob *io;
39b72d60 145{
cb69d88e
KB
146 register int ctlr = io->i_ctlr, slave = io->i_unit;
147 register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit];
bff99b3e
SL
148 register struct vddevice *vdaddr = VDADDR(ctlr);
149 int pass = 0, type = vdtype[ctlr], error;
7d68510b 150 int devflags = dkflags[ctlr][slave]; /* starts with 0 */
4006c5e1 151
bff99b3e
SL
152again:
153 dcb.opcode = VDOP_CONFIG; /* command */
154 dcb.intflg = DCBINT_NONE;
155 dcb.nxtdcb = (struct dcb *)0; /* end of chain */
156 dcb.operrsta = 0;
7d68510b 157 dcb.devselect = slave | devflags;
bff99b3e
SL
158 dcb.trail.rstrail.ncyl = lp->d_ncylinders;
159 dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
160 if (type == VDTYPE_SMDE) {
bdfd2fb7 161 dcb.trailcnt = sizeof (struct treset) / sizeof (long);
bff99b3e 162 dcb.trail.rstrail.nsectors = lp->d_nsectors;
7d68510b
MK
163 dcb.trail.rstrail.slip_sec = lp->d_trackskew;
164 dcb.trail.rstrail.recovery = VDRF_NORMAL;
bff99b3e
SL
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;
39b72d60 179 }
7d68510b
MK
180 if ((dcb.operrsta & VDERR_HARD) == 0) { /* success */
181 dkflags[ctlr][slave] = devflags;
bff99b3e 182 return (1);
7d68510b
MK
183 }
184 if (devflags == 0) {
185 devflags = VD_ESDI;
186 goto again;
187 }
bff99b3e
SL
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 }
7d68510b 196 devflags = 0;
bff99b3e
SL
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);
39b72d60 205 }
7f6fe1b4 206 DELAY(62000000);
bff99b3e 207 goto again;
39b72d60
SL
208}
209
bff99b3e
SL
210vdcmd(ctlr, unit, cmd, time)
211 register int ctlr;
212 int unit, cmd, time;
39b72d60 213{
bff99b3e 214 register struct vddevice *vdaddr = VDADDR(ctlr);
39b72d60 215
bff99b3e
SL
216 dcb.opcode = cmd;
217 dcb.intflg = DCBINT_NONE;
218 dcb.nxtdcb = (struct dcb *)0; /* end of chain */
39b72d60 219 dcb.operrsta = 0;
7d68510b 220 dcb.devselect = unit | dkflags[ctlr][unit];
bff99b3e
SL
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);
39b72d60
SL
228}
229
bff99b3e 230vdstrategy(io, cmd)
4006c5e1 231 register struct iob *io;
bff99b3e 232 int cmd;
39b72d60 233{
bff99b3e 234 register struct disklabel *lp;
7d68510b 235 int ctlr, cn, tn, sn, slave, retries = 0;
bff99b3e
SL
236 daddr_t bn;
237 struct vddevice *vdaddr;
4006c5e1
SL
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);
d4285b3c 242 io->i_error = EIO;
4006c5e1 243 return (-1);
39b72d60 244 }
cb69d88e 245 lp = &dklabel[io->i_ctlr][io->i_unit];
bff99b3e
SL
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;
39b72d60 251
7d68510b 252top:
bff99b3e
SL
253 dcb.opcode = (cmd == READ ? VDOP_RD : VDOP_WD);
254 dcb.intflg = DCBINT_NONE;
255 dcb.nxtdcb = (struct dcb *)0; /* end of chain */
39b72d60 256 dcb.operrsta = 0;
cb69d88e
KB
257 ctlr = io->i_ctlr;
258 slave = io->i_unit;
7d68510b 259 dcb.devselect = slave | dkflags[ctlr][slave];
bdfd2fb7
MK
260 dcb.trailcnt = sizeof (struct trrw) / sizeof (int);
261 dcb.trail.rwtrail.memadr = (u_long)io->i_ma;
bff99b3e
SL
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;
bff99b3e
SL
268 vdaddr = VDADDR(ctlr);
269 VDGO(vdaddr, (u_long)&mdcb, vdtype[ctlr]);
270 if (!vdpoll(vdaddr, &dcb, 60, vdtype[ctlr]))
4006c5e1 271 _stop(" during i/o operation.\n");
bff99b3e 272 if (dcb.operrsta & VDERR_HARD) {
7d68510b
MK
273 if (retries++ == 0 && vdreset_ctlr(ctlr, io->i_unit) == 0 &&
274 vdreset_drive(io))
275 goto top;
bff99b3e
SL
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);
39b72d60
SL
282}
283
bff99b3e
SL
284vderror(unit, cmd, dcb)
285 int unit;
286 char *cmd;
287 struct dcb *dcb;
39b72d60 288{
4006c5e1 289
bff99b3e
SL
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);
39b72d60 294 printf("\n");
39b72d60
SL
295}
296
1a9cb196 297/*
bff99b3e
SL
298 * Poll controller until operation
299 * completes or timeout expires.
1a9cb196 300 */
bff99b3e
SL
301vdpoll(vdaddr, dcb, t, type)
302 register struct vddevice *vdaddr;
303 register struct dcb *dcb;
1a9cb196
SL
304 register int t, type;
305{
306
307 t *= 1000;
d4285b3c 308 for (;;) {
1a9cb196 309 uncache(&dcb->operrsta);
bff99b3e 310 if (dcb->operrsta & (DCBS_DONE|DCBS_ABORT))
d4285b3c 311 break;
1a9cb196
SL
312 if (--t <= 0) {
313 printf("vd: controller timeout");
bff99b3e 314 VDABORT(vdaddr, type);
1a9cb196
SL
315 DELAY(30000);
316 uncache(&dcb->operrsta);
317 return (0);
318 }
d4285b3c 319 DELAY(1000);
1a9cb196 320 }
bff99b3e 321 if (type == VDTYPE_SMDE) {
d4285b3c 322 for (;;) {
bff99b3e
SL
323 uncache(&vdaddr->vdcsr);
324 if ((vdaddr->vdcsr & CS_GO) == 0)
d4285b3c
SL
325 break;
326 DELAY(50);
1a9cb196
SL
327 }
328 DELAY(300);
7f6fe1b4 329 uncache(&dcb->err_code);
1a9cb196
SL
330 }
331 DELAY(200);
332 uncache(&dcb->operrsta);
333 return (1);
334}
bff99b3e
SL
335
336#ifdef COMPAT_42
337struct dkcompat {
338 int nsectors; /* sectors per track */
339 int ntracks; /* tracks per cylinder */
340 int ncylinders; /* cylinders per drive */
7d68510b 341 int secsize; /* sector size */
bff99b3e
SL
342#define NPART 2
343 int poff[NPART]; /* [a+b] for bootstrapping */
344} dkcompat[] = {
7d68510b
MK
345 { 48, 24, 711, 512, 0, 61056 }, /* xsd */
346 { 44, 20, 842, 512, 0, 52800 }, /* eagle */
347 { 64, 10, 823, 512, 0, 38400 }, /* fuji 360 */
348 { 32, 24, 711, 512, 0, 40704 }, /* xfd */
349 { 32, 19, 823, 512, 0, 40128 }, /* smd */
350 { 32, 10, 823, 512, 0, 19200 }, /* fsd */
351 { 18, 15, 1224, 1024, 0, 21600 }, /* mxd */
bff99b3e
SL
352};
353#define NDKCOMPAT (sizeof (dkcompat) / sizeof (dkcompat[0]))
354
355/*
356 * Identify and configure drive from above table
357 * by trying to read the last sector until a description
358 * is found for which we're successful.
359 */
360vdmaptype(io)
361 struct iob *io;
362{
cb69d88e 363 register struct disklabel *lp = &dklabel[io->i_ctlr][io->i_unit];
bff99b3e 364 register struct dkcompat *dp;
7d68510b 365 int i, ctlr, slave, type;
bff99b3e
SL
366 struct vddevice *vdaddr;
367
cb69d88e
KB
368 ctlr = io->i_ctlr;
369 slave = io->i_unit;
bff99b3e
SL
370 vdaddr = VDADDR(ctlr);
371 type = vdtype[ctlr];
372 for (dp = dkcompat; dp < &dkcompat[NDKCOMPAT]; dp++) {
373 if (type == VDTYPE_VDDC && dp->nsectors != 32)
374 continue;
375 lp->d_nsectors = dp->nsectors;
376 lp->d_ntracks = dp->ntracks;
377 lp->d_ncylinders = dp->ncylinders;
7d68510b 378 lp->d_secsize = dp->secsize;
bff99b3e
SL
379 if (!vdreset_drive(io)) /* set drive parameters */
380 return (EIO);
381 dcb.opcode = VDOP_RD;
382 dcb.intflg = DCBINT_NONE;
383 dcb.nxtdcb = (struct dcb *)0; /* end of chain */
7d68510b 384 dcb.devselect = slave | dkflags[ctlr][slave];
bff99b3e 385 dcb.operrsta = 0;
bdfd2fb7
MK
386 dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
387 dcb.trail.rwtrail.memadr = (u_long)lbuf;
7d68510b 388 dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof (short);
bff99b3e
SL
389 dcb.trail.rwtrail.disk.cylinder = dp->ncylinders - 2;
390 dcb.trail.rwtrail.disk.track = dp->ntracks - 1;
391 dcb.trail.rwtrail.disk.sector = dp->nsectors - 1;
392 mdcb.mdcb_head = &dcb;
393 mdcb.mdcb_status = 0;
394 VDGO(vdaddr, (u_long)&mdcb, type);
395 if (!vdpoll(vdaddr, &dcb, 60, type))
396 _stop(" during i/o operation.\n");
397 if (dcb.operrsta & VDERR_HARD)
398 continue;
399 /* simulate necessary parts of disk label */
400 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
401 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
402 lp->d_npartitions = NPART;
403 for (i = 0; i < NPART; i++) {
404 lp->d_partitions[i].p_offset = dp->poff[i];
405 lp->d_partitions[i].p_size =
406 lp->d_secperunit - dp->poff[i];
407 }
408 return (0);
409 }
410 printf("dk%d: unknown drive type\n", io->i_unit);
411 return (ENXIO);
412}
413#endif