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