BSD 4_3_Tahoe development
[unix-history] / usr / src / sys / tahoestand / vd.c
CommitLineData
7fa7373f
C
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])
24long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 };
25
26u_char vdinit[NVD]; /* controller initialized */
27u_char vdtype[NVD]; /* controller type */
28u_char dkconfigured[NVD][NDRIVE]; /* unit configured */
29u_char dkflags[NVD][NDRIVE]; /* unit flags */
30
31static struct disklabel dklabel[NVD][NDRIVE]; /* pack label */
32static struct mdcb mdcb;
33static struct dcb dcb;
34static char lbuf[DEV_BSIZE];
35
36vdopen(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 */
100vdreset_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 */
143vdreset_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
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;
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
210vdcmd(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
230vdstrategy(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
252top:
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
284vderror(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 */
301vdpoll(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
337struct 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 */
361vdmaptype(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