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