|
|
1.1 root 1: /*
2: * Copyright (c) 1988 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.12 (Berkeley) 6/28/90
24: */
25:
26: #include "dk.h"
27: #if NVD > 0
28: /*
29: * Versabus VDDC/SMDE driver.
30: */
31: #include "param.h"
32: #include "buf.h"
33: #include "cmap.h"
34: #include "conf.h"
35: #include "dkstat.h"
36: #include "disklabel.h"
37: #include "map.h"
38: #include "file.h"
39: #include "systm.h"
40: #include "user.h"
41: #include "vmmac.h"
42: #include "proc.h"
43: #include "syslog.h"
44: #include "kernel.h"
45: #include "ioctl.h"
46: #include "stat.h"
47:
48: #include "../tahoe/cpu.h"
49: #include "../tahoe/mtpr.h"
50: #include "../tahoe/pte.h"
51:
52: #include "../tahoevba/vbavar.h"
53: #include "../tahoevba/vdreg.h"
54:
55: #ifndef COMPAT_42
56: #define COMPAT_42
57: #endif
58: #define B_FORMAT B_XXX /* XXX */
59:
60: #define vdunit(dev) (minor(dev) >> 3)
61: #define vdpart(dev) (minor(dev) & 0x07)
62: #define vdminor(unit,part) (((unit) << 3) | (part))
63:
64: struct vba_ctlr *vdminfo[NVD];
65: struct vba_device *vddinfo[NDK];
66: int vdprobe(), vdslave(), vdattach(), vddgo(), vdstrategy();
67: long vdstd[] = { 0xffff2000, 0xffff2100, 0xffff2200, 0xffff2300, 0 };
68: struct vba_driver vddriver =
69: { vdprobe, vdslave, vdattach, vddgo, vdstd, "dk", vddinfo, "vd", vdminfo };
70:
71: /*
72: * Per-controller state.
73: */
74: struct vdsoftc {
75: u_short vd_flags;
76: #define VD_PRINT 0x1 /* controller info printed */
77: #define VD_STARTED 0x2 /* start command issued */
78: #define VD_DOSEEKS 0x4 /* should overlap seeks */
79: #define VD_SCATGATH 0x8 /* can do scatter-gather commands (correctly) */
80: #define VD_LOCKED 0x10 /* locked for direct controller access */
81: #define VD_WAIT 0x20 /* someone needs direct controller access */
82: u_short vd_type; /* controller type */
83: u_short vd_wticks; /* timeout */
84: u_short vd_secsize; /* sector size for controller */
85: struct mdcb vd_mdcb; /* master command block */
86: u_long vd_mdcbphys; /* physical address of vd_mdcb */
87: struct dcb vd_dcb; /* i/o command block */
88: u_long vd_dcbphys; /* physical address of vd_dcb */
89: struct vb_buf vd_rbuf; /* vba resources */
90: } vdsoftc[NVD];
91:
92: #define VDMAXTIME 20 /* max time for operation, sec. */
93:
94: /*
95: * Per-drive state.
96: */
97: struct dksoftc {
98: int dk_state; /* open fsm */
99: #ifndef SECSIZE
100: u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */
101: #endif SECSIZE
102: int dk_wlabel; /* label sector is currently writable */
103: u_long dk_copenpart; /* character units open on this drive */
104: u_long dk_bopenpart; /* block units open on this drive */
105: u_long dk_openpart; /* all units open on this drive */
106: u_int dk_curcyl; /* last selected cylinder */
107: struct skdcb dk_dcb; /* seek command block */
108: u_long dk_dcbphys; /* physical address of dk_dcb */
109: int df_reg[3]; /* for formatting, in-out parameters */
110: } dksoftc[NDK];
111:
112: /*
113: * Drive states. Used during steps of open/initialization.
114: * States < OPEN (> 0) are transient, during an open operation.
115: * OPENRAW is used for unlabeled disks, to allow format operations.
116: */
117: #define CLOSED 0 /* disk is closed */
118: #define WANTOPEN 1 /* open requested, not started */
119: #define WANTOPENRAW 2 /* open requested, no label */
120: #define RDLABEL 3 /* reading pack label */
121: #define OPEN 4 /* intialized and ready */
122: #define OPENRAW 5 /* open, no label */
123:
124: struct buf dkutab[NDK]; /* i/o queue headers */
125: struct disklabel dklabel[NDK]; /* pack labels */
126:
127: #define b_cylin b_resid
128: #define b_track b_error /* used for seek commands */
129: #define b_seekf b_forw /* second queue on um_tab */
130: #define b_seekl b_back /* second queue on um_tab */
131:
132: int vdwstart, vdwatch();
133:
134: /*
135: * See if the controller is really there; if so, initialize it.
136: */
137: vdprobe(reg, vm)
138: caddr_t reg;
139: struct vba_ctlr *vm;
140: {
141: register br, cvec; /* must be r12, r11 */
142: register struct vddevice *vdaddr = (struct vddevice *)reg;
143: struct vdsoftc *vd;
144: int s;
145:
146: #ifdef lint
147: br = 0; cvec = br; br = cvec;
148: vdintr(0);
149: #endif
150: if (badaddr((caddr_t)reg, 2))
151: return (0);
152: vd = &vdsoftc[vm->um_ctlr];
153: vdaddr->vdreset = 0xffffffff;
154: DELAY(1000000);
155: if (vdaddr->vdreset != (unsigned)0xffffffff) {
156: vd->vd_type = VDTYPE_VDDC;
157: vd->vd_flags &= ~VD_DOSEEKS;
158: DELAY(1000000);
159: } else {
160: vd->vd_type = VDTYPE_SMDE;
161: vd->vd_flags |= VD_DOSEEKS;
162: vdaddr->vdrstclr = 0;
163: DELAY(3000000);
164: }
165: vd->vd_mdcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_mdcb);
166: vd->vd_dcbphys = vtoph((struct proc *)0, (unsigned)&vd->vd_dcb);
167: vm->um_addr = reg; /* XXX */
168: s = spl7();
169: if (vdinit_ctlr(vm, vd) == 0) {
170: splx(s);
171: return (0);
172: }
173: if (vd->vd_type == VDTYPE_SMDE) {
174: #ifdef notdef
175: /*
176: * Attempt PROBE to get all drive status;
177: * we take advantage of this in vdreset_drive
178: * to try to avoid guessing games.
179: */
180: (void) vdcmd(vm, VDOP_PROBE, 5, 0);
181: #endif
182: /*
183: * Check for scatter-gather by checking firmware date
184: * with IDENT command. The date is printed when
185: * vdslave is first called, thus this must be
186: * the last controller operation in vdprobe.
187: */
188: vd->vd_dcb.trail.idtrail.date = 0;
189: if (vdcmd(vm, VDOP_IDENT, 10, 0)) {
190: uncache(&vd->vd_dcb.trail.idtrail.date);
191: if (vd->vd_dcb.trail.idtrail.date != 0)
192: vd->vd_flags |= VD_SCATGATH;
193: }
194: }
195: splx(s);
196: /*
197: * Allocate page tables and i/o buffer.
198: */
199: if (vbainit(&vd->vd_rbuf, MAXPHYS,
200: vd->vd_type == VDTYPE_VDDC ? VB_24BIT : VB_32BIT) == 0) {
201: printf("vd%d: vbainit failed\n", vm->um_ctlr);
202: return (0);
203: }
204: br = 0x17, cvec = 0xe0 + vm->um_ctlr; /* XXX */
205: return (sizeof (struct vddevice));
206: }
207:
208: /*
209: * See if a drive is really there.
210: *
211: * Can't read pack label here as various data structures
212: * aren't setup for doing a read in a straightforward
213: * manner. Instead just probe for the drive and leave
214: * the pack label stuff to the attach routine.
215: */
216: /* ARGSUSED */
217: vdslave(vi, vdaddr)
218: register struct vba_device *vi;
219: struct vddevice *vdaddr;
220: {
221: register struct disklabel *lp = &dklabel[vi->ui_unit];
222: register struct dksoftc *dk = &dksoftc[vi->ui_unit];
223: struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
224: int bcd();
225:
226: if ((vd->vd_flags&VD_PRINT) == 0) {
227: printf("vd%d: %s controller", vi->ui_ctlr,
228: vd->vd_type == VDTYPE_VDDC ? "VDDC" : "SMDE");
229: if (vd->vd_flags & VD_SCATGATH) {
230: char rev[5];
231:
232: bcopy((caddr_t)&vd->vd_dcb.trail.idtrail.rev, rev,
233: sizeof(vd->vd_dcb.trail.idtrail.rev));
234: printf(" firmware rev %s (%d-%d-%d)", rev,
235: bcd((vd->vd_dcb.trail.idtrail.date >> 8) & 0xff),
236: bcd(vd->vd_dcb.trail.idtrail.date & 0xff),
237: bcd((vd->vd_dcb.trail.idtrail.date >> 16)&0xffff));
238: }
239: printf("\n");
240: vd->vd_flags |= VD_PRINT;
241: }
242:
243: /*
244: * Initialize label enough to do a reset on
245: * the drive. The remainder of the default
246: * label values will be filled in in vdinit
247: * at attach time.
248: */
249: if (vd->vd_type == VDTYPE_SMDE)
250: lp->d_secsize = VD_MAXSECSIZE;
251: else
252: lp->d_secsize = VDDC_SECSIZE;
253: lp->d_nsectors = 66; /* only used on smd-e */
254: lp->d_ntracks = 23;
255: lp->d_ncylinders = 850;
256: lp->d_secpercyl = 66*23;
257: lp->d_rpm = 3600;
258: lp->d_npartitions = 1;
259: lp->d_partitions[0].p_offset = 0;
260: lp->d_partitions[0].p_size = LABELSECTOR + 1;
261:
262: /*
263: * Initialize invariant portion of
264: * dcb used for overlapped seeks.
265: */
266: dk->dk_dcb.opcode = VDOP_SEEK;
267: dk->dk_dcb.intflg = DCBINT_NONE | DCBINT_PBA;
268: dk->dk_dcb.devselect = vi->ui_slave;
269: dk->dk_dcb.trailcnt = sizeof (struct trseek) / sizeof (long);
270: dk->dk_dcb.trail.sktrail.skaddr.sector = 0;
271: dk->dk_dcbphys = vtoph((struct proc *)0, (unsigned)&dk->dk_dcb);
272: #ifndef SECSIZE
273: vd_setsecsize(dk, lp);
274: #endif
275: return (vdreset_drive(vi));
276: }
277:
278: static int
279: bcd(n)
280: register u_int n;
281: {
282: register int bin = 0;
283: register int mul = 1;
284:
285: while (n) {
286: bin += (n & 0xf) * mul;
287: n >>= 4;
288: mul *= 10;
289: }
290: return (bin);
291: }
292:
293: vdattach(vi)
294: register struct vba_device *vi;
295: {
296: register int unit = vi->ui_unit;
297: register struct disklabel *lp = &dklabel[unit];
298:
299: /*
300: * Try to initialize device and read pack label.
301: */
302: if (vdinit(vdminor(unit, 0), 0) != 0) {
303: printf(": unknown drive type");
304: return;
305: }
306: if (dksoftc[unit].dk_state == OPEN)
307: printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>",
308: lp->d_typename, lp->d_secsize,
309: lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors);
310: /*
311: * (60 / rpm) / (sectors per track * (bytes per sector / 2))
312: */
313: if (vi->ui_dk >= 0)
314: dk_wpms[vi->ui_dk] =
315: (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120;
316: #ifdef notyet
317: addswap(makedev(VDMAJOR, vdminor(unit, 0)), lp);
318: #endif
319: }
320:
321: vdopen(dev, flags, fmt)
322: dev_t dev;
323: int flags, fmt;
324: {
325: register unit = vdunit(dev);
326: register struct disklabel *lp;
327: register struct dksoftc *dk;
328: register struct partition *pp;
329: struct vba_device *vi;
330: int s, error = 0, part = vdpart(dev), mask = 1 << part;
331: daddr_t start, end;
332:
333: if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
334: return (ENXIO);
335: lp = &dklabel[unit];
336: dk = &dksoftc[unit];
337:
338: s = spl7();
339: while (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
340: dk->dk_state != CLOSED)
341: if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, devopn, 0))
342: break;
343: splx(s);
344: if (error)
345: return (error);
346: if (dk->dk_state != OPEN && dk->dk_state != OPENRAW)
347: if (error = vdinit(dev, flags))
348: return (error);
349:
350: if (vdwstart == 0) {
351: timeout(vdwatch, (caddr_t)0, hz);
352: vdwstart++;
353: }
354: /*
355: * Warn if a partion is opened
356: * that overlaps another partition which is open
357: * unless one is the "raw" partition (whole disk).
358: */
359: #define RAWPART 8 /* 'x' partition */ /* XXX */
360: if ((dk->dk_openpart & mask) == 0 && part != RAWPART) {
361: pp = &lp->d_partitions[part];
362: start = pp->p_offset;
363: end = pp->p_offset + pp->p_size;
364: for (pp = lp->d_partitions;
365: pp < &lp->d_partitions[lp->d_npartitions]; pp++) {
366: if (pp->p_offset + pp->p_size <= start ||
367: pp->p_offset >= end)
368: continue;
369: if (pp - lp->d_partitions == RAWPART)
370: continue;
371: if (dk->dk_openpart & (1 << (pp - lp->d_partitions)))
372: log(LOG_WARNING,
373: "dk%d%c: overlaps open partition (%c)\n",
374: unit, part + 'a',
375: pp - lp->d_partitions + 'a');
376: }
377: }
378: if (part >= lp->d_npartitions)
379: return (ENXIO);
380: dk->dk_openpart |= mask;
381: switch (fmt) {
382: case S_IFCHR:
383: dk->dk_copenpart |= mask;
384: break;
385: case S_IFBLK:
386: dk->dk_bopenpart |= mask;
387: break;
388: }
389: return (0);
390: }
391:
392: /* ARGSUSED */
393: vdclose(dev, flags, fmt)
394: dev_t dev;
395: int flags, fmt;
396: {
397: register int unit = vdunit(dev);
398: register struct dksoftc *dk = &dksoftc[unit];
399: int part = vdpart(dev), mask = 1 << part;
400:
401: switch (fmt) {
402: case S_IFCHR:
403: dk->dk_copenpart &= ~mask;
404: break;
405: case S_IFBLK:
406: dk->dk_bopenpart &= ~mask;
407: break;
408: }
409: if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0)
410: dk->dk_openpart &= ~mask;
411: /*
412: * Should wait for i/o to complete on this partition
413: * even if others are open, but wait for work on blkflush().
414: */
415: if (dk->dk_openpart == 0) {
416: int s = spl7();
417: while (dkutab[unit].b_actf)
418: sleep((caddr_t)dk, PZERO-1);
419: splx(s);
420: dk->dk_state = CLOSED;
421: dk->dk_wlabel = 0;
422: }
423: return (0);
424: }
425:
426: vdinit(dev, flags)
427: dev_t dev;
428: int flags;
429: {
430: register struct disklabel *lp;
431: register struct dksoftc *dk;
432: struct vba_device *vi;
433: int unit = vdunit(dev), error = 0;
434: char *msg, *readdisklabel();
435: extern int cold;
436:
437: dk = &dksoftc[unit];
438: if (flags & O_NDELAY) {
439: dk->dk_state = OPENRAW;
440: return (0);
441: }
442: dk->dk_state = RDLABEL;
443: lp = &dklabel[unit];
444: vi = vddinfo[unit];
445: if (msg = readdisklabel(dev, vdstrategy, lp)) {
446: if (cold) {
447: printf(": %s", msg);
448: dk->dk_state = CLOSED;
449: } else {
450: log(LOG_ERR, "dk%d: %s\n", unit, msg);
451: dk->dk_state = OPENRAW;
452: }
453: #ifdef COMPAT_42
454: vdlock(vi->ui_ctlr);
455: if (vdmaptype(vi, lp))
456: dk->dk_state = OPEN;
457: vdunlock(vi->ui_ctlr);
458: #endif
459: } else {
460: /*
461: * Now that we have the label, configure
462: * the correct drive parameters.
463: */
464: vdlock(vi->ui_ctlr);
465: if (vdreset_drive(vi))
466: dk->dk_state = OPEN;
467: else {
468: dk->dk_state = CLOSED;
469: error = ENXIO;
470: }
471: vdunlock(vi->ui_ctlr);
472: }
473: #ifndef SECSIZE
474: vd_setsecsize(dk, lp);
475: #endif
476: wakeup((caddr_t)dk);
477: return (error);
478: }
479:
480: #ifndef SECSIZE
481: vd_setsecsize(dk, lp)
482: register struct dksoftc *dk;
483: register struct disklabel *lp;
484: {
485: int mul;
486:
487: /*
488: * Calculate scaling shift for mapping
489: * DEV_BSIZE blocks to drive sectors.
490: */
491: mul = DEV_BSIZE / lp->d_secsize;
492: dk->dk_bshift = 0;
493: while ((mul >>= 1) > 0)
494: dk->dk_bshift++;
495: }
496: #endif SECSIZE
497:
498: /*ARGSUSED*/
499: vddgo(vm)
500: struct vba_device *vm;
501: {
502:
503: }
504:
505: vdstrategy(bp)
506: register struct buf *bp;
507: {
508: register struct vba_device *vi;
509: register struct disklabel *lp;
510: register struct dksoftc *dk;
511: register int unit;
512: register daddr_t sn;
513: struct buf *dp;
514: daddr_t sz, maxsz;
515: int part, s;
516:
517: unit = vdunit(bp->b_dev);
518: if (unit >= NDK) {
519: bp->b_error = ENXIO;
520: goto bad;
521: }
522: vi = vddinfo[unit];
523: lp = &dklabel[unit];
524: if (vi == 0 || vi->ui_alive == 0) {
525: bp->b_error = ENXIO;
526: goto bad;
527: }
528: dk = &dksoftc[unit];
529: if (dk->dk_state < OPEN) {
530: if (dk->dk_state == CLOSED) {
531: bp->b_error = EIO;
532: goto bad;
533: }
534: goto q;
535: }
536: if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) {
537: bp->b_error = EROFS;
538: goto bad;
539: }
540: part = vdpart(bp->b_dev);
541: if ((dk->dk_openpart & (1 << part)) == 0) {
542: bp->b_error = ENODEV;
543: goto bad;
544: }
545: sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize;
546: maxsz = lp->d_partitions[part].p_size;
547: #ifndef SECSIZE
548: sn = bp->b_blkno << dk->dk_bshift;
549: #else SECSIZE
550: sn = bp->b_blkno;
551: #endif SECSIZE
552: if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR &&
553: #if LABELSECTOR != 0
554: sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR &&
555: #endif
556: (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) {
557: bp->b_error = EROFS;
558: goto bad;
559: }
560: if (sn < 0 || sn + sz > maxsz) {
561: if (sn == maxsz) {
562: bp->b_resid = bp->b_bcount;
563: goto done;
564: }
565: sz = maxsz - sn;
566: if (sz <= 0) {
567: bp->b_error = EINVAL;
568: goto bad;
569: }
570: bp->b_bcount = sz * lp->d_secsize;
571: }
572: bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl;
573: #ifdef SECSIZE
574: if (bp->b_blksize != lp->d_secsize && (bp->b_flags & B_PGIN) == 0)
575: panic("vdstrat blksize");
576: #endif SECSIZE
577: q:
578: s = spl7();
579: dp = &dkutab[vi->ui_unit];
580: disksort(dp, bp);
581: if (!dp->b_active) {
582: (void) vdustart(vi);
583: if (!vi->ui_mi->um_tab.b_active)
584: vdstart(vi->ui_mi);
585: }
586: splx(s);
587: return;
588: bad:
589: bp->b_flags |= B_ERROR;
590: done:
591: biodone(bp);
592: return;
593: }
594:
595: vdustart(vi)
596: register struct vba_device *vi;
597: {
598: register struct buf *bp, *dp;
599: register struct vba_ctlr *vm;
600: register int unit = vi->ui_unit;
601: register struct dksoftc *dk;
602: register struct vdsoftc *vd;
603: struct disklabel *lp;
604:
605: dp = &dkutab[unit];
606: /*
607: * If queue empty, nothing to do.
608: */
609: if ((bp = dp->b_actf) == NULL)
610: return;
611: /*
612: * If drive is off-cylinder and controller supports seeks,
613: * place drive on seek queue for controller.
614: * Otherwise, place on transfer queue.
615: */
616: vd = &vdsoftc[vi->ui_ctlr];
617: dk = &dksoftc[unit];
618: vm = vi->ui_mi;
619: if (bp->b_cylin != dk->dk_curcyl && vd->vd_flags&VD_DOSEEKS) {
620: lp = &dklabel[unit];
621: bp->b_track = (bp->b_blkno % lp->d_secpercyl) / lp->d_nsectors;
622: if (vm->um_tab.b_seekf == NULL)
623: vm->um_tab.b_seekf = dp;
624: else
625: vm->um_tab.b_seekl->b_forw = dp;
626: vm->um_tab.b_seekl = dp;
627: } else {
628: if (vm->um_tab.b_actf == NULL)
629: vm->um_tab.b_actf = dp;
630: else
631: vm->um_tab.b_actl->b_forw = dp;
632: vm->um_tab.b_actl = dp;
633: }
634: dp->b_forw = NULL;
635: dp->b_active++;
636: }
637:
638: /*
639: * Start next transfer on a controller.
640: * There are two queues of drives, the first on-cylinder
641: * and the second off-cylinder from their next transfers.
642: * Perform the first transfer for the first drive on the on-cylinder
643: * queue, if any, otherwise the first transfer for the first drive
644: * on the second queue. Initiate seeks on remaining drives on the
645: * off-cylinder queue, then move them all to the on-cylinder queue.
646: */
647: vdstart(vm)
648: register struct vba_ctlr *vm;
649: {
650: register struct buf *bp;
651: register struct vba_device *vi;
652: register struct vdsoftc *vd;
653: register struct dksoftc *dk;
654: register struct disklabel *lp;
655: register struct dcb **dcbp;
656: struct buf *dp;
657: int sn, tn;
658:
659: loop:
660: /*
661: * Pull a request off the controller queue.
662: */
663: if ((dp = vm->um_tab.b_actf) == NULL &&
664: (dp = vm->um_tab.b_seekf) == NULL)
665: return;
666: if ((bp = dp->b_actf) == NULL) {
667: if (dp == vm->um_tab.b_actf)
668: vm->um_tab.b_actf = dp->b_forw;
669: else
670: vm->um_tab.b_seekf = dp->b_forw;
671: goto loop;
672: }
673:
674: /*
675: * Mark controller busy, and determine
676: * destination of this request.
677: */
678: vm->um_tab.b_active++;
679: vi = vddinfo[vdunit(bp->b_dev)];
680: dk = &dksoftc[vi->ui_unit];
681: #ifndef SECSIZE
682: sn = bp->b_blkno << dk->dk_bshift;
683: #else SECSIZE
684: sn = bp->b_blkno;
685: #endif SECSIZE
686: lp = &dklabel[vi->ui_unit];
687: sn %= lp->d_secpercyl;
688: tn = sn / lp->d_nsectors;
689: sn %= lp->d_nsectors;
690:
691: /*
692: * Construct dcb for read/write command.
693: */
694: vd = &vdsoftc[vm->um_ctlr];
695: vd->vd_dcb.intflg = DCBINT_DONE;
696: vd->vd_dcb.devselect = dk->dk_dcb.devselect;
697: vd->vd_dcb.operrsta = 0;
698: vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
699: vd->vd_dcb.trail.rwtrail.disk.cylinder = bp->b_cylin;
700: vd->vd_dcb.trail.rwtrail.disk.track = tn;
701: vd->vd_dcb.trail.rwtrail.disk.sector = sn;
702: dk->dk_curcyl = bp->b_cylin;
703: bp->b_track = 0; /* init overloaded field */
704: vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
705: if (bp->b_flags & B_FORMAT)
706: vd->vd_dcb.opcode = dk->dk_op;
707: else if (vd->vd_flags & VD_SCATGATH &&
708: ((int)bp->b_un.b_addr & (sizeof(long) - 1)) == 0)
709: vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RAS : VDOP_GAW;
710: else
711: vd->vd_dcb.opcode = (bp->b_flags & B_READ)? VDOP_RD : VDOP_WD;
712:
713: switch (vd->vd_dcb.opcode) {
714: case VDOP_FSECT:
715: vd->vd_dcb.trailcnt = sizeof (struct trfmt) / sizeof (long);
716: vd->vd_dcb.trail.fmtrail.nsectors = bp->b_bcount /
717: lp->d_secsize;
718: vd->vd_dcb.trail.fmtrail.hdr = *(dskadr *)&dk->dk_althdr;
719: vd->vd_dcb.trail.rwtrail.disk.cylinder |= dk->dk_fmtflags;
720: goto setupaddr;
721:
722: case VDOP_RDRAW:
723: case VDOP_RD:
724: case VDOP_RHDE:
725: case VDOP_WD:
726: vd->vd_dcb.trail.rwtrail.wcount = (bp->b_bcount+1) >> 1;
727: setupaddr:
728: vd->vd_dcb.trail.rwtrail.memadr =
729: vbasetup(bp, &vd->vd_rbuf, (int)lp->d_secsize);
730: break;
731:
732: case VDOP_RAS:
733: case VDOP_GAW:
734: vd->vd_dcb.trailcnt += vd_sgsetup(bp, &vd->vd_rbuf,
735: &vd->vd_dcb.trail.sgtrail);
736: break;
737: }
738: if (vi->ui_dk >= 0) {
739: dk_busy |= 1<<vi->ui_dk;
740: dk_xfer[vi->ui_dk]++;
741: dk_wds[vi->ui_dk] += bp->b_bcount>>6;
742: }
743:
744: /*
745: * Look for any seeks to be performed on other drives on this
746: * controller. If overlapped seeks exist, insert seek commands
747: * on the controller's command queue before the transfer.
748: */
749: dcbp = &vd->vd_mdcb.mdcb_head;
750:
751: if (dp == vm->um_tab.b_seekf)
752: dp = dp->b_forw;
753: else
754: dp = vm->um_tab.b_seekf;
755: for (; dp != NULL; dp = dp->b_forw) {
756: if ((bp = dp->b_actf) == NULL)
757: continue;
758: vi = vddinfo[vdunit(bp->b_dev)];
759: dk = &dksoftc[vi->ui_unit];
760: dk->dk_curcyl = bp->b_cylin;
761: if (vi->ui_dk >= 0)
762: dk_seek[vi->ui_dk]++;
763: dk->dk_dcb.operrsta = 0;
764: dk->dk_dcb.trail.sktrail.skaddr.cylinder = bp->b_cylin;
765: dk->dk_dcb.trail.sktrail.skaddr.track = bp->b_track;
766: *dcbp = (struct dcb *)dk->dk_dcbphys;
767: dcbp = &dk->dk_dcb.nxtdcb;
768: }
769: *dcbp = (struct dcb *)vd->vd_dcbphys;
770: if (vm->um_tab.b_actf)
771: vm->um_tab.b_actl->b_forw = vm->um_tab.b_seekf;
772: else
773: vm->um_tab.b_actf = vm->um_tab.b_seekf;
774: if (vm->um_tab.b_seekf)
775: vm->um_tab.b_actl = vm->um_tab.b_seekl;
776: vm->um_tab.b_seekf = 0;
777:
778: /*
779: * Initiate operation.
780: */
781: vd->vd_mdcb.mdcb_status = 0;
782: VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
783: }
784:
785: /*
786: * Wait for controller to finish current operation
787: * so that direct controller accesses can be done.
788: */
789: vdlock(ctlr)
790: {
791: register struct vba_ctlr *vm = vdminfo[ctlr];
792: register struct vdsoftc *vd = &vdsoftc[ctlr];
793: int s;
794:
795: s = spl7();
796: while (vm->um_tab.b_active || vd->vd_flags & VD_LOCKED) {
797: vd->vd_flags |= VD_WAIT;
798: sleep((caddr_t)vd, PRIBIO);
799: }
800: vd->vd_flags |= VD_LOCKED;
801: splx(s);
802: }
803:
804: /*
805: * Continue normal operations after pausing for
806: * munging the controller directly.
807: */
808: vdunlock(ctlr)
809: {
810: register struct vba_ctlr *vm = vdminfo[ctlr];
811: register struct vdsoftc *vd = &vdsoftc[ctlr];
812:
813: vd->vd_flags &= ~VD_LOCKED;
814: if (vd->vd_flags & VD_WAIT) {
815: vd->vd_flags &= ~VD_WAIT;
816: wakeup((caddr_t)vd);
817: } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
818: vdstart(vm);
819: }
820:
821: #define DONTCARE (DCBS_DSE|DCBS_DSL|DCBS_TOP|DCBS_TOM|DCBS_FAIL|DCBS_DONE)
822: /*
823: * Handle a disk interrupt.
824: */
825: vdintr(ctlr)
826: register ctlr;
827: {
828: register struct buf *bp, *dp;
829: register struct vba_ctlr *vm = vdminfo[ctlr];
830: register struct vba_device *vi;
831: register struct vdsoftc *vd = &vdsoftc[ctlr];
832: register status;
833: int timedout;
834: struct dksoftc *dk;
835:
836: if (!vm->um_tab.b_active) {
837: printf("vd%d: stray interrupt\n", ctlr);
838: return;
839: }
840: /*
841: * Get device and block structures, and a pointer
842: * to the vba_device for the drive.
843: */
844: dp = vm->um_tab.b_actf;
845: bp = dp->b_actf;
846: vi = vddinfo[vdunit(bp->b_dev)];
847: dk = &dksoftc[vi->ui_unit];
848: if (vi->ui_dk >= 0)
849: dk_busy &= ~(1<<vi->ui_dk);
850: timedout = (vd->vd_wticks >= VDMAXTIME);
851: /*
852: * Check for and process errors on
853: * either the drive or the controller.
854: */
855: uncache(&vd->vd_dcb.operrsta);
856: status = vd->vd_dcb.operrsta;
857: if (bp->b_flags & B_FORMAT) {
858: dk->dk_operrsta = status;
859: uncache(&vd->vd_dcb.err_code);
860: /* ecodecnt gets err_code + err_wcnt from the same longword */
861: dk->dk_ecodecnt = *(long *)&vd->vd_dcb.err_code;
862: uncache(&vd->vd_dcb.err_trk);
863: /* erraddr gets error trk/sec/cyl from the same longword */
864: dk->dk_erraddr = *(long *)&vd->vd_dcb.err_trk;
865: } else if (status & VDERR_HARD || timedout) {
866: if (vd->vd_type == VDTYPE_SMDE)
867: uncache(&vd->vd_dcb.err_code);
868: if (status & DCBS_WPT) {
869: /*
870: * Give up on write locked devices immediately.
871: */
872: printf("dk%d: write locked\n", vi->ui_unit);
873: bp->b_flags |= B_ERROR;
874: } else if (status & VDERR_RETRY || timedout) {
875: if (status & VDERR_CTLR || timedout) {
876: vdharderr(timedout ?
877: "controller timeout" : "controller err",
878: vd, bp, &vd->vd_dcb);
879: printf("; resetting controller...");
880: vdreset_ctlr(vm);
881: } else if (status & VDERR_DRIVE) {
882: vdharderr("drive err", vd, bp, &vd->vd_dcb);
883: printf("; resetting drive...");
884: if (!vdreset_drive(vi))
885: dk->dk_state = CLOSED;
886: } else
887: vdharderr("data err", vd, bp, &vd->vd_dcb);
888: /*
889: * Retry transfer once, unless reset failed.
890: */
891: if (!vi->ui_alive || dp->b_errcnt++ >= 1) {
892: printf("\n");
893: goto hard;
894: }
895:
896: printf(" retrying\n");
897: vm->um_tab.b_active = 0; /* force retry */
898: } else {
899: vdharderr("hard error", vd, bp, &vd->vd_dcb);
900: printf("\n");
901: hard:
902: bp->b_flags |= B_ERROR;
903: }
904: } else if (status & DCBS_SOFT)
905: vdsofterr(bp, &vd->vd_dcb);
906: if (vd->vd_wticks > 3) {
907: vd->vd_dcb.err_code = vd->vd_wticks;
908: vdharderr("slow transfer (ecode is sec.)", vd, bp, &vd->vd_dcb);
909: printf("\n");
910: }
911: vd->vd_wticks = 0;
912: if (vm->um_tab.b_active) {
913: vm->um_tab.b_active = 0;
914: vm->um_tab.b_actf = dp->b_forw;
915: dp->b_active = 0;
916: dp->b_errcnt = 0;
917: dp->b_actf = bp->av_forw;
918: bp->b_resid = 0;
919: vbadone(bp, &vd->vd_rbuf);
920: biodone(bp);
921: /*
922: * If this unit has more work to do,
923: * then start it up right away.
924: */
925: if (dp->b_actf)
926: vdustart(vi);
927: else if (dk->dk_openpart == 0)
928: wakeup((caddr_t)dk);
929: }
930: /*
931: * If there are devices ready to
932: * transfer, start the controller.
933: */
934: if (vd->vd_flags & VD_WAIT) {
935: vd->vd_flags &= ~VD_WAIT;
936: wakeup((caddr_t)vd);
937: } else if (vm->um_tab.b_actf || vm->um_tab.b_seekf)
938: vdstart(vm);
939: }
940:
941: vdharderr(what, vd, bp, dcb)
942: char *what;
943: struct vdsoftc *vd;
944: register struct buf *bp;
945: register struct dcb *dcb;
946: {
947: int unit = vdunit(bp->b_dev), status = dcb->operrsta;
948: register struct disklabel *lp = &dklabel[unit];
949: int blkdone;
950:
951: if (vd->vd_wticks < VDMAXTIME)
952: status &= ~DONTCARE;
953: blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
954: lp->d_nsectors + dcb->err_sec -
955: lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
956: dksoftc[unit].dk_bshift) - bp->b_blkno;
957: diskerr(bp, "dk", what, LOG_PRINTF, blkdone, lp);
958: printf(", status %b", status, VDERRBITS);
959: if (vd->vd_type == VDTYPE_SMDE)
960: printf(" ecode %x", dcb->err_code);
961: }
962:
963: vdsofterr(bp, dcb)
964: register struct buf *bp;
965: register struct dcb *dcb;
966: {
967: int unit = vdunit(bp->b_dev);
968: struct disklabel *lp = &dklabel[unit];
969: int status = dcb->operrsta;
970: int blkdone;
971:
972: blkdone = ((((dcb->err_cyl & 0xfff) * lp->d_ntracks + dcb->err_trk) *
973: lp->d_nsectors + dcb->err_sec -
974: lp->d_partitions[vdpart(bp->b_dev)].p_offset) >>
975: dksoftc[unit].dk_bshift) - bp->b_blkno;
976:
977: if (status != (DCBS_CCD|DCBS_SOFT|DCBS_ERR|DCBS_DONE)) {
978: diskerr(bp, "dk", "soft error", LOG_WARNING, blkdone, lp);
979: addlog(", status %b ecode %x\n", status, VDERRBITS,
980: dcb->err_code);
981: } else {
982: diskerr(bp, "dk", "soft ecc", LOG_WARNING, blkdone, lp);
983: addlog("\n");
984: }
985: }
986:
987: vdioctl(dev, cmd, data, flag)
988: dev_t dev;
989: int cmd;
990: caddr_t data;
991: int flag;
992: {
993: register int unit = vdunit(dev);
994: register struct disklabel *lp = &dklabel[unit];
995: register struct dksoftc *dk = &dksoftc[unit];
996: int error = 0, vdformat();
997:
998: switch (cmd) {
999:
1000: case DIOCGDINFO:
1001: *(struct disklabel *)data = *lp;
1002: break;
1003:
1004: case DIOCGPART:
1005: ((struct partinfo *)data)->disklab = lp;
1006: ((struct partinfo *)data)->part =
1007: &lp->d_partitions[vdpart(dev)];
1008: break;
1009:
1010: case DIOCSDINFO:
1011: if ((flag & FWRITE) == 0)
1012: error = EBADF;
1013: else
1014: error = setdisklabel(lp, (struct disklabel *)data,
1015: (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart);
1016: if (error == 0 && dk->dk_state == OPENRAW &&
1017: vdreset_drive(vddinfo[unit]))
1018: dk->dk_state = OPEN;
1019: break;
1020:
1021: case DIOCWLABEL:
1022: if ((flag & FWRITE) == 0)
1023: error = EBADF;
1024: else
1025: dk->dk_wlabel = *(int *)data;
1026: break;
1027:
1028: case DIOCWDINFO:
1029: if ((flag & FWRITE) == 0)
1030: error = EBADF;
1031: else if ((error = setdisklabel(lp, (struct disklabel *)data,
1032: (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) {
1033: int wlab;
1034:
1035: if (error == 0 && dk->dk_state == OPENRAW &&
1036: vdreset_drive(vddinfo[unit]))
1037: dk->dk_state = OPEN;
1038: /* simulate opening partition 0 so write succeeds */
1039: dk->dk_openpart |= (1 << 0); /* XXX */
1040: wlab = dk->dk_wlabel;
1041: dk->dk_wlabel = 1;
1042: error = writedisklabel(dev, vdstrategy, lp);
1043: dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;
1044: dk->dk_wlabel = wlab;
1045: }
1046: break;
1047:
1048: case DIOCWFORMAT:
1049: {
1050: register struct format_op *fop;
1051: struct uio auio;
1052: struct iovec aiov;
1053:
1054: if ((flag & FWRITE) == 0) {
1055: error = EBADF;
1056: break;
1057: }
1058: fop = (struct format_op *)data;
1059: aiov.iov_base = fop->df_buf;
1060: aiov.iov_len = fop->df_count;
1061: auio.uio_iov = &aiov;
1062: auio.uio_iovcnt = 1;
1063: auio.uio_resid = fop->df_count;
1064: auio.uio_segflg = UIO_USERSPACE;
1065: auio.uio_offset = fop->df_startblk * lp->d_secsize;
1066: /* This assumes one active format operation per disk... */
1067: dk->dk_op = fop->dk_op;
1068: dk->dk_althdr = fop->dk_althdr;
1069: dk->dk_fmtflags = fop->dk_fmtflags;
1070: /*
1071: * Don't return errors, as the format op won't get copied
1072: * out if we return nonzero. Callers must check the returned
1073: * registers and count.
1074: */
1075: error = physio(vdformat, (struct buf *)NULL, dev,
1076: B_WRITE, minphys, &auio);
1077: if (error == EIO)
1078: error = 0;
1079: fop->df_count -= auio.uio_resid;
1080: /* This assumes one active format operation per disk... */
1081: fop->dk_operrsta = dk->dk_operrsta;
1082: fop->dk_ecodecnt = dk->dk_ecodecnt;
1083: fop->dk_erraddr = dk->dk_erraddr;
1084: break;
1085: }
1086:
1087: default:
1088: error = ENOTTY;
1089: break;
1090: }
1091: return (error);
1092: }
1093:
1094: vdformat(bp)
1095: struct buf *bp;
1096: {
1097: bp->b_flags |= B_FORMAT;
1098: vdstrategy(bp);
1099: }
1100:
1101: /*
1102: * Watch for lost interrupts.
1103: */
1104: vdwatch()
1105: {
1106: register struct vdsoftc *vd;
1107: register struct vba_ctlr *vm;
1108: register int ctlr;
1109: int s;
1110:
1111: timeout(vdwatch, (caddr_t)0, hz);
1112: for (ctlr = 0; ctlr < NVD; ctlr++) {
1113: vm = vdminfo[ctlr];
1114: if (vm == 0 || vm->um_alive == 0)
1115: continue;
1116: vd = &vdsoftc[ctlr];
1117: s = spl7();
1118: if (vm->um_tab.b_active && vd->vd_wticks++ >= VDMAXTIME) {
1119: printf("vd%d: lost interrupt\n", ctlr);
1120: #ifdef maybe
1121: VDABORT((struct vddevice *)vm->um_addr, vd->vd_type);
1122: #endif
1123: vdintr(ctlr);
1124: }
1125: splx(s);
1126: }
1127: }
1128:
1129: #define DBSIZE 64 /* controller limit with 1K sectors */
1130: /*
1131: * Crash dump.
1132: */
1133: vddump(dev)
1134: dev_t dev;
1135: {
1136: register struct vba_device *vi;
1137: register struct vba_ctlr *vm;
1138: register struct disklabel *lp;
1139: register struct vdsoftc *vd;
1140: struct dksoftc *dk;
1141: int part, unit, num;
1142: u_long start;
1143:
1144: start = 0;
1145: unit = vdunit(dev);
1146: if (unit > NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0)
1147: return (ENXIO);
1148: dk = &dksoftc[unit];
1149: if (dk->dk_state != OPEN && dk->dk_state != OPENRAW &&
1150: vdinit(vdminor(unit, 0), 0) != 0)
1151: return (ENXIO);
1152: lp = &dklabel[unit];
1153: part = vdpart(dev);
1154: if (part >= lp->d_npartitions)
1155: return (ENXIO);
1156: vm = vi->ui_mi;
1157: vdreset_ctlr(vm);
1158: if (dumplo < 0)
1159: return (EINVAL);
1160: /*
1161: * Maxfree is in pages, dumplo is in DEV_BSIZE units.
1162: */
1163: num = maxfree * (NBPG / lp->d_secsize);
1164: dumplo *= DEV_BSIZE / lp->d_secsize;
1165: if (dumplo + num >= lp->d_partitions[vdpart(dev)].p_size)
1166: num = lp->d_partitions[vdpart(dev)].p_size - dumplo;
1167: vd = &vdsoftc[vm->um_ctlr];
1168: vd->vd_dcb.intflg = DCBINT_NONE;
1169: vd->vd_dcb.opcode = VDOP_WD;
1170: vd->vd_dcb.devselect = dk->dk_dcb.devselect;
1171: vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
1172: while (num > 0) {
1173: int nsec, cn, sn, tn;
1174:
1175: nsec = MIN(num, DBSIZE);
1176: sn = dumplo + start / lp->d_secsize;
1177: cn = (sn + lp->d_partitions[vdpart(dev)].p_offset) /
1178: lp->d_secpercyl;
1179: sn %= lp->d_secpercyl;
1180: tn = sn / lp->d_nsectors;
1181: sn %= lp->d_nsectors;
1182: vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1183: vd->vd_dcb.trail.rwtrail.memadr = start;
1184: vd->vd_dcb.trail.rwtrail.wcount = (nsec * lp->d_secsize) >> 1;
1185: vd->vd_dcb.trail.rwtrail.disk.cylinder = cn;
1186: vd->vd_dcb.trail.rwtrail.disk.track = tn;
1187: vd->vd_dcb.trail.rwtrail.disk.sector = sn;
1188: vd->vd_dcb.operrsta = 0;
1189: VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1190: if (!vdpoll(vm, 5)) {
1191: printf(" during dump\n");
1192: return (EIO);
1193: }
1194: if (vd->vd_dcb.operrsta & VDERR_HARD) {
1195: printf("dk%d: hard error, status=%b\n", unit,
1196: vd->vd_dcb.operrsta, VDERRBITS);
1197: return (EIO);
1198: }
1199: start += nsec * lp->d_secsize;
1200: num -= nsec;
1201: }
1202: return (0);
1203: }
1204:
1205: vdsize(dev)
1206: dev_t dev;
1207: {
1208: register int unit = vdunit(dev);
1209: register struct dksoftc *dk;
1210: struct vba_device *vi;
1211: struct disklabel *lp;
1212:
1213: if (unit >= NDK || (vi = vddinfo[unit]) == 0 || vi->ui_alive == 0 ||
1214: (dk = &dksoftc[unit])->dk_state != OPEN)
1215: return (-1);
1216: lp = &dklabel[unit];
1217: #ifdef SECSIZE
1218: return ((int)lp->d_partitions[vdpart(dev)].p_size);
1219: #else SECSIZE
1220: return ((int)lp->d_partitions[vdpart(dev)].p_size >> dk->dk_bshift);
1221: #endif SECSIZE
1222: }
1223:
1224: /*
1225: * Initialize controller.
1226: */
1227: vdinit_ctlr(vm, vd)
1228: struct vba_ctlr *vm;
1229: struct vdsoftc *vd;
1230: {
1231: register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1232:
1233: if (vd->vd_type == VDTYPE_SMDE) {
1234: vdaddr->vdcsr = 0;
1235: vdaddr->vdtcf_mdcb = AM_ENPDA;
1236: vdaddr->vdtcf_dcb = AM_ENPDA;
1237: vdaddr->vdtcf_trail = AM_ENPDA;
1238: vdaddr->vdtcf_data = AM_ENPDA;
1239: vdaddr->vdccf = CCF_SEN | CCF_DIU | CCF_STS | CCF_RFE |
1240: XMD_32BIT | BSZ_16WRD |
1241: CCF_ENP | CCF_EPE | CCF_EDE | CCF_ECE | CCF_ERR;
1242: }
1243: if (!vdcmd(vm, VDOP_INIT, 10, 0) || !vdcmd(vm, VDOP_DIAG, 10, 0)) {
1244: printf("vd%d: %s cmd failed\n", vm->um_ctlr,
1245: vd->vd_dcb.opcode == VDOP_INIT ? "init" : "diag");
1246: return (0);
1247: }
1248: vd->vd_secsize = vdaddr->vdsecsize << 1;
1249: return (1);
1250: }
1251:
1252: /*
1253: * Perform a controller reset.
1254: */
1255: vdreset_ctlr(vm)
1256: register struct vba_ctlr *vm;
1257: {
1258: register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1259: register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1260: register int unit;
1261: struct vba_device *vi;
1262:
1263: VDRESET(vdaddr, vd->vd_type);
1264: if (vdinit_ctlr(vm, vd) == 0)
1265: return;
1266: for (unit = 0; unit < NDK; unit++)
1267: if ((vi = vddinfo[unit])->ui_mi == vm && vi->ui_alive)
1268: (void) vdreset_drive(vi);
1269: }
1270:
1271: vdreset_drive(vi)
1272: register struct vba_device *vi;
1273: {
1274: register struct disklabel *lp = &dklabel[vi->ui_unit];
1275: struct vba_ctlr *vm = vdminfo[vi->ui_ctlr];
1276: struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1277: register struct vdsoftc *vd = &vdsoftc[vi->ui_ctlr];
1278: register struct dksoftc *dk = &dksoftc[vi->ui_unit];
1279: int config_status, config_ecode, saw_drive = 0;
1280:
1281: #ifdef notdef
1282: /*
1283: * check for ESDI distribution panel already configured,
1284: * e.g. on boot drive, or if PROBE on controller actually
1285: * worked. Status will be zero if drive hasn't
1286: * been probed yet.
1287: */
1288: #if STA_ESDI != 0
1289: if ((vdaddr->vdstatus[vi->ui_slave] & STA_TYPE) == STA_ESDI)
1290: lp->d_devflags |= VD_ESDI;
1291: #endif
1292: #endif
1293: top:
1294: vd->vd_dcb.opcode = VDOP_CONFIG; /* command */
1295: vd->vd_dcb.intflg = DCBINT_NONE;
1296: vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
1297: vd->vd_dcb.operrsta = 0;
1298: vd->vd_dcb.devselect = vi->ui_slave | lp->d_devflags;
1299: vd->vd_dcb.trail.rstrail.ncyl = lp->d_ncylinders;
1300: vd->vd_dcb.trail.rstrail.nsurfaces = lp->d_ntracks;
1301: if (vd->vd_type == VDTYPE_SMDE) {
1302: vd->vd_dcb.trailcnt = sizeof (struct treset) / sizeof (long);
1303: vd->vd_dcb.trail.rstrail.nsectors = lp->d_nsectors;
1304: vd->vd_dcb.trail.rstrail.slip_sec = lp->d_sparespertrack;
1305: vd->vd_dcb.trail.rstrail.recovery =
1306: (lp->d_flags & D_REMOVABLE) ? VDRF_NORMAL :
1307: (VDRF_NORMAL &~ (VDRF_OSP|VDRF_OSM));
1308: } else
1309: vd->vd_dcb.trailcnt = 2; /* XXX */
1310: vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1311: vd->vd_mdcb.mdcb_status = 0;
1312: VDGO(vdaddr, vd->vd_mdcbphys, vd->vd_type);
1313: if (!vdpoll(vm, 5)) {
1314: printf(" during config\n");
1315: return (0);
1316: }
1317: config_status = vd->vd_dcb.operrsta;
1318: config_ecode = (u_char)vd->vd_dcb.err_code;
1319: if (config_status & VDERR_HARD) {
1320: if (vd->vd_type == VDTYPE_SMDE) {
1321: /*
1322: * If drive status was updated successfully,
1323: * STA_US (unit selected) should be set
1324: * if the drive is attached and powered up.
1325: * (But only if we've guessed right on SMD
1326: * vs. ESDI; if that flag is wrong, we won't
1327: * see the drive.) If we don't see STA_US
1328: * with either SMD or ESDI set for the unit,
1329: * we assume that the drive doesn't exist,
1330: * and don't wait for it to spin up.
1331: */
1332: (void) vdcmd(vm, VDOP_STATUS, 5, vi->ui_slave);
1333: uncache(&vdaddr->vdstatus[vi->ui_slave]);
1334: if (vdaddr->vdstatus[vi->ui_slave] & STA_US)
1335: saw_drive = 1;
1336: else if (lp->d_devflags == 0) {
1337: lp->d_devflags = VD_ESDI;
1338: goto top;
1339: }
1340: } else
1341: saw_drive = 1;
1342: if ((config_status & (DCBS_OCYL|DCBS_NRDY)) == 0)
1343: printf("dk%d: config error %b ecode %x\n", vi->ui_unit,
1344: config_status, VDERRBITS, config_ecode);
1345: else if ((vd->vd_flags & VD_STARTED) == 0 && saw_drive) {
1346: int started;
1347:
1348: printf(" starting drives, wait ... ");
1349: vd->vd_flags |= VD_STARTED;
1350: started = (vdcmd(vm, VDOP_START, 10) == 1);
1351: DELAY(62000000);
1352: printf("done\n");
1353: lp->d_devflags = 0;
1354: if (started)
1355: goto top;
1356: }
1357: return (0);
1358: }
1359: dk->dk_dcb.devselect |= lp->d_devflags;
1360: return (1);
1361: }
1362:
1363: /*
1364: * Perform a command w/o trailer.
1365: */
1366: vdcmd(vm, cmd, t, slave)
1367: register struct vba_ctlr *vm;
1368: {
1369: register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1370:
1371: vd->vd_dcb.opcode = cmd; /* command */
1372: vd->vd_dcb.intflg = DCBINT_NONE;
1373: vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
1374: vd->vd_dcb.operrsta = 0;
1375: vd->vd_dcb.devselect = slave;
1376: vd->vd_dcb.trailcnt = 0;
1377: vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1378: vd->vd_mdcb.mdcb_status = 0;
1379: VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1380: if (!vdpoll(vm, t)) {
1381: printf(" during init\n");
1382: return (0);
1383: }
1384: return ((vd->vd_dcb.operrsta&VDERR_HARD) == 0);
1385: }
1386:
1387: /*
1388: * Poll controller until operation
1389: * completes or timeout expires.
1390: */
1391: vdpoll(vm, t)
1392: register struct vba_ctlr *vm;
1393: register int t;
1394: {
1395: register struct vdsoftc *vd = &vdsoftc[vm->um_ctlr];
1396: register struct vddevice *vdaddr = (struct vddevice *)vm->um_addr;
1397:
1398: t *= 1000;
1399: for (;;) {
1400: uncache(&vd->vd_dcb.operrsta);
1401: if (vd->vd_dcb.operrsta & (DCBS_DONE|DCBS_ABORT))
1402: break;
1403: if (--t <= 0) {
1404: printf("vd%d: controller timeout", vm->um_ctlr);
1405: VDABORT(vdaddr, vd->vd_type);
1406: return (0);
1407: }
1408: DELAY(1000);
1409: }
1410: if (vd->vd_type == VDTYPE_SMDE) {
1411: do {
1412: DELAY(50);
1413: uncache(&vdaddr->vdcsr);
1414: } while (vdaddr->vdcsr & CS_GO);
1415: DELAY(300);
1416: uncache(&vd->vd_dcb.err_code);
1417: }
1418: DELAY(200);
1419: uncache(&vd->vd_dcb.operrsta);
1420: return (1);
1421: }
1422:
1423: #ifdef COMPAT_42
1424: struct vdst {
1425: int nsec; /* sectors/track */
1426: int ntrack; /* tracks/cylinder */
1427: int ncyl; /* cylinders */
1428: int secsize; /* sector size */
1429: char *name; /* type name */
1430: struct {
1431: int off; /* partition offset in sectors */
1432: int size; /* partition size in sectors */
1433: } parts[8];
1434: } vdst[] = {
1435: { 66, 23, 850, 512, "NEC 800",
1436: {0, 1290300}, /* a cyl 0 - 849 */
1437: },
1438: { 64, 20, 842, 512, "2361a",
1439: {0, 61440}, /* a cyl 0 - 47 */
1440: {61440, 67840}, /* b cyl 48 - 100 */
1441: {129280, 942080}, /* c cyl 101 - 836 */
1442: {0, 1071360}, /* d cyl 0 - 836 */
1443: {449280, 311040}, /* e cyl 351 - 593 */
1444: {760320, 311040}, /* f cyl 594 - 836 */
1445: {449280, 622080}, /* g cyl 351 - 836 */
1446: {129280, 320000} /* h cyl 101 - 350 */
1447: },
1448: { 48, 24, 711, 512, "xsd",
1449: {0, 61056}, /* a cyl 0 - 52 */
1450: {61056, 61056}, /* b cyl 53 - 105 */
1451: {122112, 691200}, /* c cyl 106 - 705 */
1452: {237312, 576000}, /* d cyl 206 - 705 */
1453: {352512, 460800}, /* e cyl 306 - 705 */
1454: {467712, 345600}, /* f cyl 406 - 705 */
1455: {582912, 230400}, /* g cyl 506 - 705 */
1456: {698112, 115200} /* h cyl 606 - 705 */
1457: },
1458: { 44, 20, 842, 512, "eagle",
1459: {0, 52800}, /* egl0a cyl 0 - 59 */
1460: {52800, 66000}, /* egl0b cyl 60 - 134 */
1461: {118800, 617760}, /* egl0c cyl 135 - 836 */
1462: {736560, 4400}, /* egl0d cyl 837 - 841 */
1463: {0, 736560}, /* egl0e cyl 0 - 836 */
1464: {0, 740960}, /* egl0f cyl 0 - 841 */
1465: {118800, 310640}, /* egl0g cyl 135 - 487 */
1466: {429440, 307120} /* egl0h cyl 488 - 836 */
1467: },
1468: { 64, 10, 823, 512, "fuj",
1469: {0, 38400}, /* fuj0a cyl 0 - 59 */
1470: {38400, 48000}, /* fuj0b cyl 60 - 134 */
1471: {86400, 437120}, /* fuj0c cyl 135 - 817 */
1472: {159360, 364160}, /* fuj0d cyl 249 - 817 */
1473: {232320, 291200}, /* fuj0e cyl 363 - 817 */
1474: {305280, 218240}, /* fuj0f cyl 477 - 817 */
1475: {378240, 145280}, /* fuj0g cyl 591 - 817 */
1476: {451200, 72320} /* fug0h cyl 705 - 817 */
1477: },
1478: { 32, 24, 711, 512, "xfd",
1479: { 0, 40704 }, /* a cyl 0 - 52 */
1480: { 40704, 40704 }, /* b cyl 53 - 105 */
1481: { 81408, 460800 }, /* c cyl 106 - 705 */
1482: { 0, 81408 }, /* d cyl 709 - 710 (a & b) */
1483: { 0, 542208 }, /* e cyl 0 - 705 */
1484: { 40704, 501504 }, /* f cyl 53 - 705 (b & c) */
1485: { 81408, 230400 }, /* g cyl 106 - 405 (1/2 of c) */
1486: { 311808,230400 } /* h cyl 406 - 705 (1/2 of c) */
1487: },
1488: { 32, 19, 823, 512, "smd",
1489: {0, 40128}, /* a cyl 0-65 */
1490: {40128, 27360}, /* b cyl 66-110 */
1491: {67488, 429856}, /* c cyl 111-817 */
1492: {139232, 358112}, /* d cyl 229 - 817 */
1493: {210976, 286368}, /* e cyl 347 - 817 */
1494: {282720, 214624}, /* f cyl 465 - 817 */
1495: {354464, 142880}, /* g cyl 583 - 817 */
1496: {426208, 71136} /* h cyl 701 - 817 */
1497: },
1498: { 18, 15, 1224, 1024, "mxd",
1499: {0, 21600}, /* a cyl 0-79 */
1500: {21600, 22410}, /* b cyl 80-162 */
1501: {44010, 285120}, /* c cyl 163-1217 */
1502: #ifdef notyet
1503: {x, 237600}, /* d cyl y - 1217 */
1504: {x, 190080}, /* e cyl y - 1217 */
1505: {x, 142560}, /* f cyl y - 1217 */
1506: {x, 95040}, /* g cyl y - 1217 */
1507: {x, 47520} /* h cyl 701 - 817 */
1508: #endif
1509: },
1510: { 32, 10, 823, 512, "fsd",
1511: {0, 19200}, /* a cyl 0 - 59 */
1512: {19200, 24000}, /* b cyl 60 - 134 */
1513: {43200, 218560}, /* c cyl 135 - 817 */
1514: }
1515: };
1516: #define NVDST (sizeof (vdst) / sizeof (vdst[0]))
1517:
1518: /*
1519: * Construct a label for an unlabeled pack. We
1520: * deduce the drive type by reading from the last
1521: * track on successively smaller drives until we
1522: * don't get an error.
1523: */
1524: vdmaptype(vi, lp)
1525: register struct vba_device *vi;
1526: register struct disklabel *lp;
1527: {
1528: register struct vdsoftc *vd;
1529: register struct vdst *p;
1530: struct vba_ctlr *vm = vi->ui_mi;
1531: int i;
1532:
1533: vd = &vdsoftc[vi->ui_ctlr];
1534: for (p = vdst; p < &vdst[NVDST]; p++) {
1535: if (vd->vd_type == VDTYPE_VDDC && p->nsec != 32)
1536: continue;
1537: lp->d_nsectors = p->nsec;
1538: lp->d_ntracks = p->ntrack;
1539: lp->d_ncylinders = p->ncyl;
1540: lp->d_secsize = p->secsize;
1541: DELAY(100000);
1542: if (!vdreset_drive(vi))
1543: return (0);
1544: DELAY(100000);
1545: vd->vd_dcb.opcode = VDOP_RD;
1546: vd->vd_dcb.intflg = DCBINT_NONE;
1547: vd->vd_dcb.nxtdcb = (struct dcb *)0; /* end of chain */
1548: vd->vd_dcb.devselect = dksoftc[vi->ui_unit].dk_dcb.devselect;
1549: vd->vd_dcb.trailcnt = sizeof (struct trrw) / sizeof (long);
1550: vd->vd_dcb.trail.rwtrail.memadr =
1551: vtoph((struct proc *)0, (unsigned)vd->vd_rbuf.vb_rawbuf);
1552: vd->vd_dcb.trail.rwtrail.wcount = lp->d_secsize / sizeof(short);
1553: vd->vd_dcb.operrsta = 0;
1554: vd->vd_dcb.trail.rwtrail.disk.cylinder = p->ncyl - 2;
1555: vd->vd_dcb.trail.rwtrail.disk.track = p->ntrack - 1;
1556: vd->vd_dcb.trail.rwtrail.disk.sector = p->nsec - 1;
1557: vd->vd_mdcb.mdcb_head = (struct dcb *)vd->vd_dcbphys;
1558: vd->vd_mdcb.mdcb_status = 0;
1559: VDGO(vm->um_addr, vd->vd_mdcbphys, vd->vd_type);
1560: if (!vdpoll(vm, 60))
1561: printf(" during probe\n");
1562: if ((vd->vd_dcb.operrsta & VDERR_HARD) == 0)
1563: break;
1564: }
1565: if (p >= &vdst[NVDST])
1566: return (0);
1567:
1568: for (i = 0; i < 8; i++) {
1569: lp->d_partitions[i].p_offset = p->parts[i].off;
1570: lp->d_partitions[i].p_size = p->parts[i].size;
1571: }
1572: lp->d_npartitions = 8;
1573: lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1574: bcopy(p->name, lp->d_typename, 4);
1575: return (1);
1576: }
1577: #endif COMPAT_42
1578: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.