|
|
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.