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