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