|
|
1.1 root 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])
24: long vdaddrs[NVD] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300 };
25:
26: u_char vdinit[NVD]; /* controller initialized */
27: u_char vdtype[NVD]; /* controller type */
28: u_char dkconfigured[NVD][NDRIVE]; /* unit configured */
29: u_char dkflags[NVD][NDRIVE]; /* unit flags */
30:
31: static struct disklabel dklabel[NVD][NDRIVE]; /* pack label */
32: static struct mdcb mdcb;
33: static struct dcb dcb;
34: static char lbuf[DEV_BSIZE];
35:
36: vdopen(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: */
100: vdreset_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: */
143: vdreset_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:
152: again:
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:
210: vdcmd(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:
230: vdstrategy(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:
252: top:
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:
284: vderror(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: */
301: vdpoll(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
337: struct 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: */
361: vdmaptype(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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.