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