|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: * ! 6: * %W% (Berkeley) %D% ! 7: */ ! 8: ! 9: /* ! 10: * up.c, driver for Emulex SC21, SC31 disk controllers ! 11: * with support for disklabels. ! 12: * UNTESTED. ! 13: */ ! 14: ! 15: #ifdef UPDEBUG ! 16: int updebug; ! 17: #endif ! 18: #ifdef UPBDEBUG ! 19: int upbdebug; ! 20: #endif ! 21: ! 22: #include "up.h" ! 23: #if NSC > 0 ! 24: /* ! 25: * UNIBUS disk driver with: ! 26: * overlapped seeks, ! 27: * ECC recovery, and ! 28: * bad sector forwarding. ! 29: * ! 30: * TODO: ! 31: * Check that offset recovery code works ! 32: */ ! 33: #include "../machine/pte.h" ! 34: ! 35: #include "param.h" ! 36: #include "systm.h" ! 37: #include "dkstat.h" ! 38: #include "dkbad.h" ! 39: #include "ioctl.h" ! 40: #include "disklabel.h" ! 41: #include "buf.h" ! 42: #include "conf.h" ! 43: #include "dir.h" ! 44: #include "file.h" ! 45: #include "user.h" ! 46: #include "map.h" ! 47: #include "vm.h" ! 48: #include "cmap.h" ! 49: #include "uio.h" ! 50: #include "kernel.h" ! 51: #include "syslog.h" ! 52: #include "stat.h" ! 53: ! 54: #include "../vax/mtpr.h" ! 55: #include "../vax/cpu.h" ! 56: #include "../vax/nexus.h" ! 57: #include "ubavar.h" ! 58: #include "ubareg.h" ! 59: #include "upreg.h" ! 60: ! 61: #define COMPAT_42 ! 62: #define B_FORMAT B_XXX ! 63: ! 64: #define upunit(dev) (minor(dev) >> 3) ! 65: #define uppart(dev) (minor(dev) & 07) ! 66: #define upminor(unit, part) (((unit) << 3) | (part)) ! 67: ! 68: int upprobe(), upslave(), upattach(), updgo(), upintr(); ! 69: struct uba_ctlr *upminfo[NSC]; ! 70: struct uba_device *updinfo[NUP]; ! 71: #define UPIPUNITS 8 ! 72: struct uba_device *upip[NSC][UPIPUNITS]; /* fuji w/fixed head gives n,n+4 */ ! 73: ! 74: u_short upstd[] = { 0776700, 0774400, 0776300, 0 }; ! 75: struct uba_driver scdriver = ! 76: { upprobe, upslave, upattach, updgo, upstd, "up", updinfo, "sc", upminfo }; ! 77: ! 78: struct buf uputab[NUP]; ! 79: char upinit[NUP]; ! 80: ! 81: u_char up_offset[16] = { ! 82: UPOF_P400, UPOF_M400, UPOF_P400, UPOF_M400, ! 83: UPOF_P800, UPOF_M800, UPOF_P800, UPOF_M800, ! 84: UPOF_P1200, UPOF_M1200, UPOF_P1200, UPOF_M1200, ! 85: 0, 0, 0, 0 ! 86: }; ! 87: ! 88: struct buf bupbuf[NUP]; ! 89: struct dkbad upbad[NUP]; ! 90: ! 91: struct upsoftc { ! 92: u_char sc_recal; /* recalibrate state */ ! 93: u_char sc_doseeks; /* perform explicit seeks */ ! 94: #ifdef COMPAT_42 ! 95: u_char sc_hdr; /* next i/o includes header */ ! 96: #endif ! 97: short sc_state; /* open fsm */ ! 98: short sc_wlabel; /* label sector is currently writeable */ ! 99: u_long sc_openpart; /* bit mask of open subunits */ ! 100: u_long sc_copenpart; /* bit mask of open character subunits */ ! 101: u_long sc_bopenpart; /* bit mask of open block subunits */ ! 102: int sc_blkdone; /* amount sucessfully transfered */ ! 103: daddr_t sc_badbn; /* replacement block number */ ! 104: short sc_softas; /* bitmask of drives needing attention */ ! 105: short sc_ndrive; /* count of drives */ ! 106: int sc_wticks; /* watchdog timer */ ! 107: int sc_status; /* copy of drive status reg after format */ ! 108: int sc_upds; /* copy of upds reg after format */ ! 109: int sc_er1; /* copy of error reg 1 after format */ ! 110: int sc_er2; /* copy of error reg 2 after format */ ! 111: } upsoftc[NSC]; ! 112: ! 113: /* ! 114: * Drive states. Used during steps of open/initialization. ! 115: * States < OPEN (> 0) are transient, during an open operation. ! 116: * OPENRAW is used for unlabeled disks, ! 117: * to inhibit bad-sector forwarding or allow format operations. ! 118: */ ! 119: #define CLOSED 0 /* disk is closed. */ ! 120: #define WANTOPEN 1 /* open requested, not started */ ! 121: #define WANTOPENRAW 2 /* open requested, no label */ ! 122: #define RDLABEL 3 /* reading pack label */ ! 123: #define RDBADTBL 4 /* reading bad-sector table */ ! 124: #define OPEN 5 /* initialized and ready */ ! 125: #define OPENRAW 6 /* open, no label or badsect */ ! 126: ! 127: #define b_cylin b_resid /* cyl number, for disksort */ ! 128: #define b_bufsiz b_bdone /* amount done, in ui_tab only */ ! 129: ! 130: int upwstart, upwatch(); /* Have started guardian */ ! 131: int upseek; ! 132: int upwaitdry; ! 133: ! 134: upprobe(reg) ! 135: caddr_t reg; ! 136: { ! 137: register int br, cvec; ! 138: ! 139: #ifdef lint ! 140: br = 0; cvec = br; br = cvec; upintr(0); ! 141: #endif ! 142: ((struct updevice *)reg)->upcs1 = UP_IE|UP_RDY; ! 143: DELAY(10); ! 144: ((struct updevice *)reg)->upcs1 = 0; ! 145: return (sizeof (struct updevice)); ! 146: } ! 147: ! 148: upslave(ui, reg) ! 149: struct uba_device *ui; ! 150: caddr_t reg; ! 151: { ! 152: register struct updevice *upaddr = (struct updevice *)reg; ! 153: ! 154: upaddr->upcs1 = 0; /* conservative */ ! 155: upaddr->upcs2 = ui->ui_slave; ! 156: upaddr->upcs1 = UP_NOP|UP_GO; ! 157: if (upaddr->upcs2&UPCS2_NED) { ! 158: upaddr->upcs1 = UP_DCLR|UP_GO; ! 159: return (0); ! 160: } ! 161: return (1); ! 162: } ! 163: ! 164: upattach(ui) ! 165: register struct uba_device *ui; ! 166: { ! 167: register int unit = ui->ui_unit; ! 168: ! 169: if (upwstart == 0) { ! 170: timeout(upwatch, (caddr_t)0, hz); ! 171: upwstart++; ! 172: } ! 173: upip[ui->ui_ctlr][ui->ui_slave] = ui; ! 174: up_softc[ui->ui_ctlr].sc_ndrive++; ! 175: ! 176: /* ! 177: * Try to initialize device and read pack label. ! 178: */ ! 179: if (upinit(upminor(unit, 0), 0) == 0) { ! 180: printf(": %s", uplabel[unit].d_typename); ! 181: #ifdef notyet ! 182: addswap(makedev(UPMAJOR, upminor(unit, 0)), &uplabel[unit]); ! 183: #endif ! 184: } else ! 185: printf(": offline"); ! 186: } ! 187: ! 188: upopen(dev, flags, fmt) ! 189: dev_t dev; ! 190: int flags, fmt; ! 191: { ! 192: register int unit = upunit(dev); ! 193: register struct upsoftc *sc; ! 194: register struct disklabel *lp; ! 195: register struct partition *pp; ! 196: struct uba_device *ui; ! 197: int s, error, part = uppart(dev), mask = 1 << part; ! 198: daddr_t start, end; ! 199: ! 200: if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0) ! 201: return (ENXIO); ! 202: ! 203: sc = &upsoftc[unit]; ! 204: lp = &uplabel[unit]; ! 205: ! 206: s = spl5(); ! 207: while (sc->sc_state != OPEN && sc->sc_state != OPENRAW && ! 208: sc->sc_state != CLOSED) ! 209: sleep ((caddr_t)sc, PZERO+1); ! 210: splx(s); ! 211: if (sc->sc_state != OPEN && sc->sc_state != OPENRAW) ! 212: if (error = upinit(dev, flags)) ! 213: return (error); ! 214: if (part >= lp->d_npartitions) ! 215: return (ENXIO); ! 216: /* ! 217: * Warn if a partion is opened ! 218: * that overlaps another partition which is open ! 219: * unless one is the "raw" partition (whole disk). ! 220: */ ! 221: #define RAWPART 2 /* 'c' partition */ /* XXX */ ! 222: if ((sc->sc_openpart & mask) == 0 && part != RAWPART) { ! 223: pp = &lp->d_partitions[part]; ! 224: start = pp->p_offset; ! 225: end = pp->p_offset + pp->p_size; ! 226: for (pp = lp->d_partitions; ! 227: pp < &lp->d_partitions[lp->d_npartitions]; pp++) { ! 228: if (pp->p_offset + pp->p_size <= start || ! 229: pp->p_offset >= end) ! 230: continue; ! 231: if ((s = pp - lp->d_partitions) == RAWPART) ! 232: continue; ! 233: if (sc->sc_openpart & (1 << s)) ! 234: log(LOG_WARNING, ! 235: "up%d%c: overlaps open partition (%c)\n", ! 236: unit, part + 'a', s + 'a'); ! 237: } ! 238: } ! 239: switch (fmt) { ! 240: case S_IFCHR: ! 241: sc->sc_copenpart |= mask; ! 242: break; ! 243: case S_IFBLK: ! 244: sc->sc_bopenpart |= mask; ! 245: break; ! 246: } ! 247: sc->sc_openpart |= mask; ! 248: return (0); ! 249: } ! 250: ! 251: /* ARGSUSED */ ! 252: upclose(dev, flags, fmt) ! 253: dev_t dev; ! 254: int flags, fmt; ! 255: { ! 256: register int unit = upunit(dev); ! 257: register struct upsoftc *sc = &upsoftc[unit]; ! 258: struct uba_device *ui = updinfo[unit]; ! 259: int s; ! 260: ! 261: switch (fmt) { ! 262: case S_IFCHR: ! 263: sc->sc_copenpart &= ~(1 << uppart(dev)); ! 264: break; ! 265: case S_IFBLK: ! 266: sc->sc_bopenpart &= ~(1 << uppart(dev)); ! 267: break; ! 268: } ! 269: if (sc->sc_openpart) ! 270: sc->sc_openpart = sc->sc_copenpart | sc->sc_bopenpart; ! 271: ! 272: /* ! 273: * If this was the last open partition on the drive, then ! 274: * we must wait for the i/o to complete (so caller knows its ! 275: * ok to turn the drive off). If not the last, no problem, ! 276: * as some other partition must still be active. (Potential ! 277: * problem is some part of the "drive" can be spun down ! 278: * while leaving other part of same drive running ..) ! 279: * ! 280: * (this will also happen if we have disabled the drive because ! 281: * of an unanticipated pack change, but no harm there) ! 282: */ ! 283: if (sc->sc_openpart == 0) { ! 284: s = spl5(); ! 285: while (ui->ui_tab.b_actf) ! 286: sleep((caddr_t)sc, PZERO - 1); ! 287: splx(s); ! 288: sc->sc_state = CLOSED; ! 289: } ! 290: return (0); ! 291: } ! 292: ! 293: upinit(dev, flags) ! 294: dev_t dev; ! 295: int flags; ! 296: { ! 297: register struct upsoftc *sc; ! 298: register struct buf *bp; ! 299: register struct disklabel *lp; ! 300: struct uba_device *ui; ! 301: struct dkbad *db; ! 302: char *msg, *readdisklabel(); ! 303: int unit, i, error = 0; ! 304: extern int cold; ! 305: ! 306: unit = upunit(dev); ! 307: sc = &upsoftc[unit]; ! 308: lp = &uplabel[unit]; ! 309: ui = updinfo[unit]; ! 310: ! 311: sc->sc_state = WANTOPEN; ! 312: ! 313: /* ! 314: * Obtain the physical drive characteristics from the ! 315: * controller, for use until the label overrides them. ! 316: */ ! 317: upphysical(ui->ui_addr, lp); ! 318: ! 319: if (flags & O_NDELAY) ! 320: goto raw; ! 321: ! 322: /* ! 323: * Preset, pack acknowledge will be done in upstart ! 324: * during first read operation. ! 325: */ ! 326: if (msg = readdisklabel(dev, upstrategy, lp)) { ! 327: if (cold) ! 328: printf(": %s", msg); ! 329: else ! 330: log(LOG_ERR, "up%d: %s\n", unit, msg); ! 331: #ifdef COMPAT_42 ! 332: if (upmaptype(ui, lp) == 0) ! 333: #endif ! 334: goto raw; ! 335: } ! 336: ! 337: /* ! 338: * Seconds per word = (60 / rpm) / (nsectors * secsize/2) ! 339: */ ! 340: if (ui->ui_dk >= 0 && lp->d_rpm) ! 341: dk_mspw[ui->ui_dk] = 120.0 / ! 342: (lp->d_rpm * lp->d_nsectors * lp->d_secsize); ! 343: /* ! 344: * Read bad sector table into memory. ! 345: */ ! 346: bp = geteblk(DEV_BSIZE); /* max sector size */ ! 347: bp->b_dev = dev; ! 348: sc->sc_state = RDBADTBL; ! 349: i = 0; ! 350: do { ! 351: u.u_error = 0; /* XXX */ ! 352: bp->b_flags = B_BUSY | B_READ; ! 353: bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i; ! 354: bp->b_bcount = lp->d_secsize; ! 355: bp->b_cylin = lp->d_ncylinders - 1; ! 356: upstrategy(bp); ! 357: biowait(bp); ! 358: } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 && ! 359: i < lp->d_nsectors); ! 360: db = (struct dkbad *)(bp->b_un.b_addr); ! 361: if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 && ! 362: db->bt_flag == 0) { ! 363: upbad[unit] = *db; ! 364: sc->sc_state = OPEN; ! 365: } else { ! 366: log(LOG_ERR, "up%d: %s bad-sector file\n", unit, ! 367: (bp->b_flags & B_ERROR) ? "can't read" : "format error in"); ! 368: u.u_error = 0; /* XXX */ ! 369: sc->sc_state = OPENRAW; ! 370: } ! 371: bp->b_flags = B_INVAL | B_AGE; ! 372: brelse(bp); ! 373: done: ! 374: wakeup((caddr_t)sc); ! 375: return (error); ! 376: ! 377: raw: ! 378: sc->sc_state = OPENRAW; ! 379: wakeup((caddr_t)sc); ! 380: return (error); ! 381: } ! 382: ! 383: /* ! 384: * obtain the physical drive layout from the controller prom ! 385: * (we know this isn't a dec controller, so we can assume sanity) ! 386: */ ! 387: upphysical(upaddr, lp) ! 388: register struct updevice *upaddr; ! 389: register struct disklabel *lp; ! 390: { ! 391: upaddr->upcs1 = 0; ! 392: upaddr->upcs2 = ui->ui_slave; ! 393: ! 394: upaddr->uphr = UPHR_MAXTRAK; ! 395: lp->d_ntracks = upaddr->uphr + 1; ! 396: ! 397: upaddr->uphr = UPHR_MAXSECT; ! 398: lp->d_nsectors = upaddr->uphr + 1; ! 399: ! 400: upaddr->uphr = UPHR_MAXCYL; ! 401: lp->d_ncylinders = upaddr->uphr + 1; ! 402: ! 403: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; ! 404: lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; ! 405: ! 406: lp->d_npartitions = 1; /* ??? (allow label write) */ ! 407: lp->d_partitions[0].p_offset = 0; ! 408: lp->d_partitions[0].p_size = lp->d_secperunit; ! 409: ! 410: lp->d_secsize = DEV_BSIZE; /* assume this */ ! 411: ! 412: upaddr->upcs2 = UPCS2_CLR; ! 413: } ! 414: ! 415: upstrategy(bp) ! 416: register struct buf *bp; ! 417: { ! 418: register struct uba_device *ui; ! 419: register struct disklabel *lp; ! 420: register struct upsoftc *sc; ! 421: register int unit; ! 422: register struct buf *dp; ! 423: long bn, sz; ! 424: daddr_t maxsz; ! 425: int xunit = uppart(bp->b_dev); ! 426: int s; ! 427: ! 428: sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; ! 429: unit = hpunit(bp->b_dev); ! 430: if (unit >= NUP) { ! 431: bp->b_error = ENXIO; ! 432: goto bad; ! 433: } ! 434: ui = updinfo[unit]; ! 435: if (ui == 0 || ui->ui_alive == 0) { ! 436: bp->b_error = ENXIO; ! 437: goto bad; ! 438: } ! 439: sc = &upsoftc[unit]; ! 440: lp = &uplabel[unit]; ! 441: if (sc->sc_state < OPEN) ! 442: goto q; ! 443: if ((sc->sc_openpart & (1 << xunit)) == 0) { ! 444: bp->b_error = ENODEV; ! 445: goto bad; ! 446: } ! 447: maxsz = lp->d_partitions[xunit].p_size; ! 448: if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { ! 449: if (bp->b_blkno == maxsz) { ! 450: bp->b_resid = bp->b_bcount; ! 451: goto done; ! 452: } ! 453: sz = maxsz - bp->b_blkno; ! 454: if (sz <= 0) { ! 455: bp->b_error = EINVAL; ! 456: goto bad; ! 457: } ! 458: bp->b_bcount = sz << DEV_BSHIFT; ! 459: } ! 460: bp->b_cylin = (bp->b_blkno + lp->d_partitions[xunit].p_offset) / ! 461: lp->d_secpercyl; ! 462: q: ! 463: s = spl5(); ! 464: dp = &uputab[ui->ui_unit]; ! 465: disksort(dp, bp); ! 466: if (dp->b_active == 0) { ! 467: (void) upustart(ui); ! 468: bp = &ui->ui_mi->um_tab; ! 469: if (bp->b_actf && bp->b_active == 0) ! 470: (void) upstart(ui->ui_mi); ! 471: } ! 472: splx(s); ! 473: return; ! 474: ! 475: bad: ! 476: bp->b_flags |= B_ERROR; ! 477: done: ! 478: biodone(bp); ! 479: return; ! 480: } ! 481: ! 482: /* ! 483: * Unit start routine. ! 484: * Seek the drive to be where the data is ! 485: * and then generate another interrupt ! 486: * to actually start the transfer. ! 487: * If there is only one drive on the controller, ! 488: * or we are very close to the data, don't ! 489: * bother with the search. If called after ! 490: * searching once, don't bother to look where ! 491: * we are, just queue for transfer (to avoid ! 492: * positioning forever without transferrring.) ! 493: */ ! 494: upustart(ui) ! 495: register struct uba_device *ui; ! 496: { ! 497: register struct buf *bp, *dp; ! 498: register struct uba_ctlr *um; ! 499: register struct updevice *upaddr; ! 500: register struct disklabel *lp; ! 501: struct upsoftc *sc = &upsoftc[ui->ui_unit]; ! 502: daddr_t bn; ! 503: int sn, tn, dist; ! 504: /* ! 505: * The SC21 cancels commands if you just say ! 506: * cs1 = UP_IE ! 507: * so we are cautious about handling of cs1. ! 508: * Also don't bother to clear as bits other than in upintr(). ! 509: */ ! 510: int didie = 0; ! 511: ! 512: if (ui == 0) ! 513: return (0); ! 514: um = ui->ui_mi; ! 515: dk_busy &= ~(1<<ui->ui_dk); ! 516: dp = &uputab[ui->ui_unit]; ! 517: retry: ! 518: if ((bp = dp->b_actf) == NULL) ! 519: return (0); ! 520: /* ! 521: * If the controller is active, just remember ! 522: * that this device would like to be positioned... ! 523: * if we tried to position now we would confuse the SC21. ! 524: */ ! 525: if (um->um_tab.b_active) { ! 526: up_softc[um->um_ctlr].sc_softas |= 1<<ui->ui_slave; ! 527: return (0); ! 528: } ! 529: /* ! 530: * If we have already positioned this drive, ! 531: * then just put it on the ready queue. ! 532: */ ! 533: if (dp->b_active) ! 534: goto done; ! 535: dp->b_active = 1; ! 536: ! 537: lp = &uplabel[ui->ui_unit]; ! 538: upaddr = (struct updevice *)um->um_addr; ! 539: upaddr->upcs2 = ui->ui_slave; ! 540: ! 541: switch (sc->sc_recal) { ! 542: ! 543: case 1: ! 544: (void)HPWAIT(mi, hpaddr); ! 545: upaddr->updc = bp->b_cylin; ! 546: upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; ! 547: sc->sc_recal++; ! 548: return (1); ! 549: case 2: ! 550: break; ! 551: } ! 552: sc->sc_recal = 0; ! 553: /* ! 554: * If drive has just come up, ! 555: * setup the pack. ! 556: */ ! 557: if ((upaddr->upds & UPDS_VV) == 0) { ! 558: struct buf *bbp = &bupbuf[ui->ui_unit]; ! 559: ! 560: if (sc->sc_state == OPEN && lp->d_flags & D_REMOVABLE) { ! 561: if (sc->sc_openpart) ! 562: log(LOG_ERR, "up%d: volume changed\n", ! 563: ui->ui_unit); ! 564: sc->sc_openpart = 0; ! 565: do { ! 566: dp->b_actf = bp->b_forw; ! 567: bp->b_flags |= B_ERROR; ! 568: bp->b_errno = ENXIO; ! 569: iodone(bp); ! 570: } while (bp = dp->b_actf); ! 571: return (0); ! 572: } ! 573: upaddr->upcs1 = UP_IE|UP_DCLR|UP_GO; ! 574: upaddr->upcs1 = UP_IE|UP_PRESET|UP_GO; ! 575: upaddr->upof = UPOF_FMT22; ! 576: if (sc->sc_state == WANTOPENRAW) { ! 577: sc->sc_state = OPENRAW; ! 578: return (1); ! 579: } ! 580: if (sc->sc_state == WANTOPEN) ! 581: sc->sc_state = RDLABEL; ! 582: didie = 1; ! 583: } ! 584: /* ! 585: * If drive is offline, forget about positioning. ! 586: */ ! 587: if ((upaddr->upds & (UPDS_DPR|UPDS_MOL)) != (UPDS_DPR|UPDS_MOL)) ! 588: goto done; ! 589: /* ! 590: * If there is only one drive, ! 591: * dont bother searching. ! 592: */ ! 593: if (up_softc[um->um_ctlr].sc_ndrive == 1) ! 594: goto done; ! 595: /* ! 596: * Figure out where this transfer is going to ! 597: * and see if we are close enough to justify not searching. ! 598: */ ! 599: st = &upst[ui->ui_type]; ! 600: bn = bp->b_blkno; ! 601: sn = bn % lp->d_secpercyl; ! 602: tn = sn / lp->d_nsectors; ! 603: sn = sn % lp->d_nsectors; ! 604: if (bp->b_cylin == upaddr->updc) { ! 605: if (sc->sc_doseeks) ! 606: goto done; /* Ok just to be on-cylinder */ ! 607: dist = sn - (upaddr->upla>>6) - 1; ! 608: if (dist < 0) ! 609: dist += lp->d_nsectors; ! 610: if (dist <= lp->d_maxdist && dist >= lp->d_mindist) ! 611: goto done; ! 612: } else ! 613: upaddr->updc = bp->b_cylin; ! 614: /* ! 615: * Not on cylinder at correct position, ! 616: * seek/search. ! 617: */ ! 618: if (sc->sc_doseeks) ! 619: upaddr->upcs1 = UP_IE|UP_SEEK|UP_GO; ! 620: else { ! 621: sn = (sn + lp->d_nsectors - lp->d_sdist) % lp->d_nsectors; ! 622: upaddr->upda = sn; ! 623: upaddr->upcs1 = UP_IE|UP_SEARCH|UP_GO; ! 624: } ! 625: didie = 1; ! 626: /* ! 627: * Mark unit busy for iostat. ! 628: */ ! 629: if (ui->ui_dk >= 0) { ! 630: dk_busy |= 1<<ui->ui_dk; ! 631: dk_seek[ui->ui_dk]++; ! 632: } ! 633: goto out; ! 634: done: ! 635: /* ! 636: * Device is ready to go. ! 637: * Put it on the ready queue for the controller ! 638: * (unless its already there.) ! 639: */ ! 640: if (dp->b_active != 2) { ! 641: dp->b_forw = NULL; ! 642: if (um->um_tab.b_actf == NULL) ! 643: um->um_tab.b_actf = dp; ! 644: else ! 645: um->um_tab.b_actl->b_forw = dp; ! 646: um->um_tab.b_actl = dp; ! 647: dp->b_active = 2; ! 648: } ! 649: out: ! 650: return (didie); ! 651: } ! 652: ! 653: /* ! 654: * Start up a transfer on a drive. ! 655: */ ! 656: upstart(um) ! 657: register struct uba_ctlr *um; ! 658: { ! 659: register struct buf *bp, *dp; ! 660: register struct uba_device *ui; ! 661: register struct updevice *upaddr; ! 662: register struct disklabel *lp = &uplabel[ui->ui_unit]; ! 663: struct upsoftc *sc = &upsoftc[ui->ui_unit]; ! 664: daddr_t bn; ! 665: int cn, dn, sn, tn, cmd, waitdry; ! 666: ! 667: loop: ! 668: /* ! 669: * Pull a request off the controller queue ! 670: */ ! 671: if ((dp = um->um_tab.b_actf) == NULL) ! 672: return (0); ! 673: if ((bp = dp->b_actf) == NULL) { ! 674: um->um_tab.b_actf = dp->b_forw; ! 675: goto loop; ! 676: } ! 677: /* ! 678: * Mark controller busy, and ! 679: * determine destination of this request. ! 680: */ ! 681: um->um_tab.b_active++; ! 682: ui = updinfo[upunit(bp->b_dev)]; ! 683: bn = bp->b_blkno; ! 684: dn = ui->ui_slave; ! 685: st = &upst[ui->ui_type]; ! 686: sn = bn%st->nspc; ! 687: tn = sn/st->nsect; ! 688: sn %= st->nsect; ! 689: upaddr = (struct updevice *)ui->ui_addr; ! 690: /* ! 691: * Select drive if not selected already. ! 692: */ ! 693: if ((upaddr->upcs2&07) != dn) ! 694: upaddr->upcs2 = dn; ! 695: /* ! 696: * Check that it is ready and online ! 697: */ ! 698: waitdry = 0; ! 699: while ((upaddr->upds&UPDS_DRY) == 0) { ! 700: log(LOG_ERR, "up%d: ds wait ds=%o\n", upunit(bp->b_dev), ! 701: upaddr->upds); ! 702: if (++waitdry > 512) ! 703: break; ! 704: upwaitdry++; ! 705: } ! 706: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 707: /* ! 708: * this should be "log()", but log with split ! 709: * messages is very messy, and we also depend here ! 710: * on there being a real (measureable) time taken ! 711: * doing the printf, to give the drive a chance to ! 712: * recover .. printf polls the terminal, so takes ages ! 713: */ ! 714: printf("up%d: not ready", upunit(bp->b_dev)); ! 715: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 716: printf("\n"); ! 717: um->um_tab.b_active = 0; ! 718: um->um_tab.b_errcnt = 0; ! 719: dp->b_actf = bp->av_forw; ! 720: dp->b_active = 0; ! 721: bp->b_flags |= B_ERROR; ! 722: iodone(bp); ! 723: goto loop; ! 724: } ! 725: /* ! 726: * Oh, well, sometimes this ! 727: * happens, for reasons unknown. ! 728: */ ! 729: printf(" (flakey)\n"); ! 730: } ! 731: /* ! 732: * Setup for the transfer, and get in the ! 733: * UNIBUS adaptor queue. ! 734: */ ! 735: if (bp->b_flags & B_BAD) { ! 736: bn = sc->sc_badbn; ! 737: cn = bn / lp->d_secpercyl; ! 738: } else { ! 739: bn = bp->b_blkno; ! 740: cn = bp->b_cylin; ! 741: } ! 742: sn = bn % lp->d_secpercyl; ! 743: if ((bp->b_flags & B_BAD) == 0) ! 744: sn += sc->sc_blkdone; ! 745: tn = sn / lp->d_nsectors; ! 746: sn %= lp->d_nsectors; ! 747: cn += tn / lp->d_ntracks; ! 748: tn %= lp->d_ntracks; ! 749: upaddr->updc = cn; ! 750: upaddr->upda = (tn << 8) + sn; ! 751: ! 752: if (bp->b_bcount >= 0) ! 753: upaddr->upwc = (-bp->b_bcount + ui->ui_tab.b_bdone) / ! 754: sizeof (short); ! 755: else ! 756: upaddr->upwc = (bp->b_wcount + ui->ui_tab.b_bdone) / ! 757: sizeof (short); ! 758: ! 759: switch (bp->b_flags & (B_READ|B_WRITE|B_FORMAT)) { ! 760: case B_READ: ! 761: cmd = UP_IE|UP_RCOM|UP_GO; ! 762: break; ! 763: case B_WRITE: ! 764: cmd = UP_IE|UP_WCOM|UP_GO; ! 765: break; ! 766: case B_READ|B_FORMAT: ! 767: cmd = UP_IE|UP_RHDR|UP_GO; ! 768: break; ! 769: case B_WRITE|B_FORMAT: ! 770: cmd = UP_IE|UP_WHDR|UP_GO; ! 771: break; ! 772: } ! 773: um->um_cmd = cmd; ! 774: ui->ui_tab.b_bdone = dbtob(sc->sc_blkdone); ! 775: (void) ubago(ui); ! 776: return (1); ! 777: } ! 778: ! 779: /* ! 780: * Now all ready to go, stuff the registers. ! 781: */ ! 782: updgo(um) ! 783: struct uba_ctlr *um; ! 784: { ! 785: register struct updevice *upaddr = (struct updevice *)um->um_addr; ! 786: ! 787: um->um_tab.b_active = 2; /* should now be 2 */ ! 788: upaddr->upba = um->um_ubinfo; ! 789: upaddr->upcs1 = um->um_cmd|((um->um_ubinfo>>8)&0x300); ! 790: } ! 791: ! 792: /* ! 793: * Handle a disk interrupt. ! 794: */ ! 795: upintr(sc21) ! 796: register sc21; ! 797: { ! 798: register struct buf *bp, *dp; ! 799: register struct uba_ctlr *um = upminfo[sc21]; ! 800: register struct uba_device *ui; ! 801: register struct updevice *upaddr = (struct updevice *)um->um_addr; ! 802: register unit; ! 803: struct up_softc *sc = &up_softc[um->um_ctlr]; ! 804: int as = (upaddr->upas & 0377) | sc->sc_softas; ! 805: int needie = 1, waitdry; ! 806: ! 807: sc->sc_wticks = 0; ! 808: sc->sc_softas = 0; ! 809: /* ! 810: * If controller wasn't transferring, then this is an ! 811: * interrupt for attention status on seeking drives. ! 812: * Just service them. ! 813: */ ! 814: if (um->um_tab.b_active != 2 && !sc->sc_recal) { ! 815: if (upaddr->upcs1 & UP_TRE) ! 816: upaddr->upcs1 = UP_TRE; ! 817: goto doattn; ! 818: } ! 819: um->um_tab.b_active = 1; ! 820: /* ! 821: * Get device and block structures, and a pointer ! 822: * to the uba_device for the drive. Select the drive. ! 823: */ ! 824: dp = um->um_tab.b_actf; ! 825: bp = dp->b_actf; ! 826: ui = updinfo[upunit(bp->b_dev)]; ! 827: dk_busy &= ~(1 << ui->ui_dk); ! 828: if ((upaddr->upcs2&07) != ui->ui_slave) ! 829: upaddr->upcs2 = ui->ui_slave; ! 830: ! 831: /* ! 832: * Check for and process errors on ! 833: * either the drive or the controller. ! 834: */ ! 835: if ((upaddr->upds&UPDS_ERR) || (upaddr->upcs1&UP_TRE)) { ! 836: er1 = upaddr->uper1; ! 837: er2 = upaddr->uper2; ! 838: if (bp->b_flags & B_BAD) { ! 839: npf = bp->b_error; ! 840: bn = sc->sc_badbn; ! 841: } else { ! 842: npf = btop(bp->b_bcount + upaddr->upwc * sizeof(short)); ! 843: if (er1 & (UPER_DCK | UPER_ECH)) ! 844: npf--; ! 845: bn = bp->b_blkno + npf; ! 846: } ! 847: if (UPWAIT(upaddr, upunit(bp->b_dev)) == 0) ! 848: goto hard; ! 849: #ifdef UPDEBUG ! 850: if (updebug) { ! 851: log(LOG_DEBUG, ! 852: "uperr: bp %x cyl %d blk %d blkdone %d as %o dc %x da %x\n", ! 853: bp, bp->b_cylin, bn, sc->sc_blkdone, ! 854: upaddr->upas, upaddr->updc, upaddr->upda); ! 855: log(LOG_DEBUG, ! 856: "errcnt %d er1 %b er2 %b wc -%d (bc %d)\n", ! 857: um->um_tab.b_errcnt, er1, UPER1_BITS, ! 858: er2, UPER2_BITS, -up->upwc,-up->upwc*sizeof(short)); ! 859: } ! 860: #endif ! 861: if (er1 & UPER1_HCRC) { ! 862: er1 &= ~(UPER1_HCE|UPER1_FER); ! 863: er2 &= ~UPER2_BSE; ! 864: } ! 865: if (er1 & UPER1_WLE) { ! 866: /* ! 867: * Give up on write locked devices ! 868: * immediately. ! 869: */ ! 870: log(LOG_WARNING, "up%d: write locked\n", ! 871: upunit(bp->b_dev)); ! 872: bp->b_flags |= B_ERROR; ! 873: } else if (bp->b_flags & B_FORMAT) { ! 874: goto hard; ! 875: } else if (er2 & UPER2_BSE) { ! 876: if (upecc(ui, BSW)) ! 877: return; ! 878: goto hard; ! 879: } else if ((er1 & (UPER1_DCK|UPER1_ECH)) == UPER1_DCK && ! 880: um->um_tab.b_errcnt >= 3) { ! 881: if (upecc(ui, ECC)) ! 882: return; ! 883: /* see comment in hp.c */ ! 884: if (ui->ui_tab.b_errcnt == 3) ! 885: ui->ui_tab.b_errcnt = 0; ! 886: } else if (er1 & UPER1_HCRC && upecc(ui, BSE)) { ! 887: return; ! 888: } else if (++um->um_tab.b_errcnt > 27 || er1 & HPER1_HARD) { ! 889: hard: ! 890: bp->b_blkno = bn; /* XXX */ ! 891: harderr(bp, "up"); ! 892: printf("cn=%d tn=%d sn=%d cs2=%b er1=%b er2=%b", ! 893: upaddr->updc, ((upaddr->upda)>>8)&077, ! 894: (upaddr->upda)&037, ! 895: upaddr->upcs2, UPCS2_BITS, ! 896: upaddr->uper1, UPER1_BITS, ! 897: upaddr->uper2, UPER2_BITS); ! 898: if (bp->b_flags & B_FORMAT) ! 899: printf(" (hdr i/o)"); ! 900: printf("\n"); ! 901: bp->b_flags |= B_ERROR; ! 902: bp->b_flags &= ~B_BAD; ! 903: } else ! 904: um->um_tab.b_active = 0; /* force retry */ ! 905: /* ! 906: * Clear drive error and, every eight attempts, ! 907: * (starting with the fourth) ! 908: * recalibrate to clear the slate. ! 909: */ ! 910: upaddr->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 911: needie = 0; ! 912: if ((um->um_tab.b_errcnt&07) == 4 && um->um_tab.b_active == 0) { ! 913: upaddr->upcs1 = UP_RECAL|UP_IE|UP_GO; ! 914: sc->sc_recal = 0; ! 915: goto nextrecal; ! 916: } ! 917: } ! 918: #ifdef UPDEBUG ! 919: else if (updebug && sc->sc_recal) { ! 920: log(LOG_DEBUG, "up: recal %d errcnt %d er1=%b er2=%b\n", ! 921: sc->sc_recal, um->um_tab.b_errcnt, ! 922: upaddr->uper1, UPER1_BITS, ! 923: upaddr->uper2, UPER2_BITS); ! 924: } ! 925: #endif ! 926: /* ! 927: * Advance recalibration finite state machine ! 928: * if recalibrate in progress, through ! 929: * RECAL ! 930: * SEEK ! 931: * OFFSET (optional) ! 932: * RETRY ! 933: */ ! 934: switch (sc->sc_recal) { ! 935: ! 936: case 1: ! 937: upaddr->updc = bp->b_cylin; ! 938: upaddr->upcs1 = UP_SEEK|UP_IE|UP_GO; ! 939: goto nextrecal; ! 940: case 2: ! 941: if (um->um_tab.b_errcnt < 16 || (bp->b_flags&B_READ) == 0) ! 942: goto donerecal; ! 943: upaddr->upof = up_offset[um->um_tab.b_errcnt&017] | UPOF_FMT22; ! 944: upaddr->upcs1 = UP_IE|UP_OFFSET|UP_GO; ! 945: goto nextrecal; ! 946: nextrecal: ! 947: sc->sc_recal++; ! 948: um->um_tab.b_active = 1; ! 949: return; ! 950: donerecal: ! 951: case 3: ! 952: sc->sc_recal = 0; ! 953: um->um_tab.b_active = 0; ! 954: break; ! 955: } ! 956: /* ! 957: * If still ``active'', then don't need any more retries. ! 958: */ ! 959: if (um->um_tab.b_active) { ! 960: /* ! 961: * If we were offset positioning, ! 962: * return to centerline. ! 963: */ ! 964: if (um->um_tab.b_errcnt >= 16) { ! 965: upaddr->upof = UPOF_FMT22; ! 966: upaddr->upcs1 = UP_RTC|UP_GO|UP_IE; ! 967: while (upaddr->upds & UPDS_PIP) ! 968: DELAY(25); ! 969: needie = 0; ! 970: } ! 971: um->um_tab.b_active = 0; ! 972: um->um_tab.b_errcnt = 0; ! 973: um->um_tab.b_actf = dp->b_forw; ! 974: dp->b_active = 0; ! 975: dp->b_errcnt = 0; ! 976: dp->b_actf = bp->av_forw; ! 977: bp->b_resid = (-upaddr->upwc * sizeof(short)); ! 978: sc->sc_blkdone = 0; ! 979: if (sc->sc_openpart == 0) ! 980: wakeup((caddr_t)sc); ! 981: iodone(bp); ! 982: /* ! 983: * If this unit has more work to do, ! 984: * then start it up right away. ! 985: */ ! 986: if (dp->b_actf) ! 987: if (upustart(ui)) ! 988: needie = 0; ! 989: } ! 990: as &= ~(1<<ui->ui_slave); ! 991: /* ! 992: * Release unibus resources and flush data paths. ! 993: */ ! 994: ubadone(um); ! 995: doattn: ! 996: /* ! 997: * Process other units which need attention. ! 998: * For each unit which needs attention, call ! 999: * the unit start routine to place the slave ! 1000: * on the controller device queue. ! 1001: */ ! 1002: while (unit = ffs((long)as)) { ! 1003: unit--; /* was 1 origin */ ! 1004: as &= ~(1<<unit); ! 1005: upaddr->upas = 1<<unit; ! 1006: if (unit < UPIPUNITS && upustart(upip[sc21][unit])) ! 1007: needie = 0; ! 1008: } ! 1009: /* ! 1010: * If the controller is not transferring, but ! 1011: * there are devices ready to transfer, start ! 1012: * the controller. ! 1013: */ ! 1014: if (um->um_tab.b_actf && um->um_tab.b_active == 0) ! 1015: if (upstart(um)) ! 1016: needie = 0; ! 1017: if (needie) ! 1018: upaddr->upcs1 = UP_IE; ! 1019: } ! 1020: ! 1021: upioctl(dev, cmd, data, flag) ! 1022: dev_t dev; ! 1023: int cmd; ! 1024: caddr_t data; ! 1025: int flag; ! 1026: { ! 1027: int unit = upunit(dev); ! 1028: register struct disklabel *lp; ! 1029: register struct format_op *fop; ! 1030: int error = 0; ! 1031: int upformat(); ! 1032: ! 1033: lp = &uplabel[unit]; ! 1034: ! 1035: switch (cmd) { ! 1036: ! 1037: case DIOCGDINFO: ! 1038: *(struct disklabel *)data = *lp; ! 1039: break; ! 1040: ! 1041: case DIOCGPART: ! 1042: ((struct partinfo *)data)->disklab = lp; ! 1043: ((struct partinfo *)data)->part = ! 1044: &lp->d_partitions[uppart(dev)]; ! 1045: break; ! 1046: ! 1047: case DIOCSDINFO: ! 1048: if ((flag & FWRITE) == 0) ! 1049: error = EBADF; ! 1050: else ! 1051: *lp = *(struct disklabel *)data; ! 1052: break; ! 1053: ! 1054: case DIOCWDINFO: ! 1055: if ((flag & FWRITE) == 0) { ! 1056: error = EBADF; ! 1057: break; ! 1058: } ! 1059: { ! 1060: struct buf *bp; ! 1061: struct disklabel *dlp; ! 1062: ! 1063: *lp = *(struct disklabel *)data; ! 1064: bp = geteblk(lp->d_secsize); ! 1065: bp->b_dev = makedev(major(dev), upminor(upunit(dev), 0)); ! 1066: bp->b_blkno = LABELSECTOR; ! 1067: bp->b_bcount = lp->d_secsize; ! 1068: bp->b_flags = B_READ; ! 1069: dlp = (struct disklabel *)(bp->b_un.b_addr + LABELOFFSET); ! 1070: upstrategy(bp); ! 1071: biowait(bp); ! 1072: if (bp->b_flags & B_ERROR) { ! 1073: error = u.u_error; /* XXX */ ! 1074: u.u_error = 0; ! 1075: goto bad; ! 1076: } ! 1077: *dlp = *lp; ! 1078: bp->b_flags = B_WRITE; ! 1079: upstrategy(bp); ! 1080: biowait(bp); ! 1081: if (bp->b_flags & B_ERROR) { ! 1082: error = u.u_error; /* XXX */ ! 1083: u.u_error = 0; ! 1084: } ! 1085: bad: ! 1086: brelse(bp); ! 1087: break; ! 1088: } ! 1089: ! 1090: #ifdef notyet ! 1091: case DIOCWFORMAT: ! 1092: if ((flag & FWRITE) == 0) { ! 1093: error = EBADF; ! 1094: break; ! 1095: } ! 1096: { ! 1097: struct uio auio; ! 1098: struct iovec aiov; ! 1099: ! 1100: fop = (struct format_op *)data; ! 1101: aiov.iov_base = fop->df_buf; ! 1102: aiov.iov_len = fop->df_count; ! 1103: auio.uio_iov = &aiov; ! 1104: auio.uio_iovcnt = 1; ! 1105: auio.uio_resid = fop->df_count; ! 1106: auio.uio_segflg = 0; ! 1107: auio.uio_offset = fop->df_startblk * lp->d_secsize; ! 1108: error = physio(upformat, &rupbuf[unit], dev, B_WRITE, ! 1109: minphys, &auio); ! 1110: fop->df_count -= auio.uio_resid; ! 1111: fop->df_reg[0] = sc->sc_status; ! 1112: fop->df_reg[1] = sc->sc_error; ! 1113: } ! 1114: break; ! 1115: #endif ! 1116: ! 1117: default: ! 1118: error = ENOTTY; ! 1119: break; ! 1120: } ! 1121: return (error); ! 1122: } ! 1123: ! 1124: upformat(bp) ! 1125: struct buf *bp; ! 1126: { ! 1127: ! 1128: bp->b_flags |= B_FORMAT; ! 1129: return (upstrategy(bp)); ! 1130: } ! 1131: ! 1132: /* ! 1133: * Correct an ECC error, and restart the i/o to complete ! 1134: * the transfer if necessary. This is quite complicated because ! 1135: * the transfer may be going to an odd memory address base and/or ! 1136: * across a page boundary. ! 1137: */ ! 1138: upecc(ui, flag) ! 1139: register struct uba_device *ui; ! 1140: int flag; ! 1141: { ! 1142: register struct updevice *up = (struct updevice *)ui->ui_addr; ! 1143: register struct buf *bp = uputab[ui->ui_unit].b_actf; ! 1144: register struct uba_ctlr *um = ui->ui_mi; ! 1145: register struct disklabel *lp = &hplabel[mi->mi_unit]; ! 1146: struct uba_regs *ubp = ui->ui_hd->uh_uba; ! 1147: struct hpsoftc *sc = &hpsoftc[mi->mi_unit]; ! 1148: register int i; ! 1149: caddr_t addr; ! 1150: int reg, bit, byte, npf, mask, o, cmd, ubaddr; ! 1151: int bn, cn, tn, sn; ! 1152: int bcr; ! 1153: ! 1154: /* ! 1155: * Npf is the number of sectors transferred before the sector ! 1156: * containing the ECC error, and reg is the UBA register ! 1157: * mapping (the first part of) the transfer. ! 1158: * O is offset within a memory page of the first byte transferred. ! 1159: */ ! 1160: bcr = -up->upwc * sizeof(short); ! 1161: if (flag == CONT) ! 1162: npf = bp->b_error; ! 1163: else { ! 1164: npf = bp->b_bcount - bcr; ! 1165: /* ! 1166: * Watch out for fractional sector at end of transfer; ! 1167: * want to round up if finished, otherwise round down. ! 1168: */ ! 1169: if (bcr == 0) ! 1170: npf += 511; ! 1171: npf = btodb(npf); ! 1172: } ! 1173: reg = btop(um->um_ubinfo&0x3ffff) + npf; ! 1174: o = (int)bp->b_un.b_addr & PGOFSET; ! 1175: mask = up->upec2; ! 1176: #ifdef UPECCDEBUG ! 1177: if (upeccdebug) ! 1178: log(LOG_DEBUG, "npf %d reg %x o %d mask %o pos %d\n", ! 1179: npf, reg, o, mask, up->upec1); ! 1180: #endif ! 1181: bn = bp->b_blkno; ! 1182: cn = bp->b_cylin; ! 1183: sn = bn % lp->d_secpercyl + npf; ! 1184: tn = sn / lp->d_nsectors; ! 1185: sn %= lp->d_nsectors; ! 1186: cn += tn / lp->d_ntracks; ! 1187: tn %= lp->d_ntracks; ! 1188: bn += npf; ! 1189: ubapurge(um); ! 1190: um->um_tab.b_active = 2; ! 1191: /* ! 1192: * action taken depends on the flag ! 1193: */ ! 1194: switch (flag) { ! 1195: case ECC: { ! 1196: register int i; ! 1197: caddr_t addr; ! 1198: struct pte mpte; ! 1199: int bit, byte, mask; ! 1200: ! 1201: npf--; /* because block in error is previous block */ ! 1202: bn--; ! 1203: reg--; ! 1204: if (bp->b_flags & B_BAD) ! 1205: bn = sc->sc_badbn; ! 1206: log(LOG_WARNING, "up%d%c: soft ecc sn%d\n", upunit(bp->b_dev), ! 1207: 'a' + uppart(bp->b_dev), bp->b_blkno + npf); ! 1208: /* ! 1209: * Flush the buffered data path, and compute the ! 1210: * byte and bit position of the error. The variable i ! 1211: * is the byte offset in the transfer, the variable byte ! 1212: * is the offset from a page boundary in main memory. ! 1213: */ ! 1214: i = up->upec1 - 1; /* -1 makes 0 origin */ ! 1215: mask = up->upec2; ! 1216: bit = i&07; ! 1217: i = (i&~07)>>3; ! 1218: byte = i + o; ! 1219: /* ! 1220: * Correct while possible bits remain of mask. Since mask ! 1221: * contains 11 bits, we continue while the bit offset is > -11. ! 1222: * Also watch out for end of this block and the end of the whole ! 1223: * transfer. ! 1224: */ ! 1225: while (i < 512 && (int)dbtob(npf)+i < bp->b_bcount && bit > -11) { ! 1226: struct pte pte; ! 1227: ! 1228: pte = ubp->uba_map[reg + btop(byte)]; ! 1229: addr = ptob(pte.pg_pfnum) + (byte & PGOFSET); ! 1230: #ifdef UPECCDEBUG ! 1231: printf("addr %x map reg %x\n", ! 1232: addr, *(int *)(&ubp->uba_map[reg+btop(byte)])); ! 1233: printf("old: %x, ", getmemc(addr)); ! 1234: #endif ! 1235: putmemc(addr, getmemc(addr)^(mask<<bit)); ! 1236: #ifdef UPECCDEBUG ! 1237: printf("new: %x\n", getmemc(addr)); ! 1238: #endif ! 1239: byte++; ! 1240: i++; ! 1241: bit -= 8; ! 1242: } ! 1243: if (bcr == 0) ! 1244: return (0); ! 1245: npf++; ! 1246: reg++; ! 1247: break; ! 1248: } ! 1249: ! 1250: case BSE: ! 1251: if (sc->sc_state == OPENRAW) ! 1252: return (0); ! 1253: #ifdef UPBDEBUG ! 1254: if (upbdebug) ! 1255: log(LOG_DEBUG, "upecc, BSE: bn %d cn %d tn %d sn %d\n", ! 1256: bn, cn, tn, sn); ! 1257: #endif ! 1258: if (bp->b_flags & B_BAD) ! 1259: return (0); ! 1260: /* ! 1261: * if not in bad sector table, return 0 ! 1262: */ ! 1263: if ((bn = isbad(&upbad[ui->ui_unit], cn, tn, sn)) < 0) ! 1264: return(0); ! 1265: /* ! 1266: * flag this one as bad ! 1267: */ ! 1268: bp->b_flags |= B_BAD; ! 1269: bp->b_error = npf + 1; ! 1270: #ifdef UPBDEBUG ! 1271: if (upbdebug) ! 1272: log(LOG_DEBUG "BSE: restart at %d\n",npf+1); ! 1273: #endif ! 1274: bn = lp->d_ncylinders * lp->d_secpercyl - ! 1275: lp->d_nsectors - 1 - bn; ! 1276: sc->sc_badbn = bn; ! 1277: fixregs: ! 1278: cn = bn / lp->d_secpercyl; ! 1279: sn = bn % lp->d_secpercyl; ! 1280: tn = sn / lp->d_nsectors; ! 1281: sn %= lp->d_nsectors; ! 1282: bcr = bp->b_bcount - (int)ptob(npf); ! 1283: bcr = MIN(bcr, 512); ! 1284: up->upwc = -bcr; ! 1285: #ifdef UPBDEBUG ! 1286: if (upbdebug) ! 1287: log(LOG_DEBUG, "revector to cn %d tn %d sn %d\n", ! 1288: cn, tn, sn); ! 1289: #endif ! 1290: break; ! 1291: ! 1292: case CONT: ! 1293: #ifdef UPBDEBUG ! 1294: if (upbdebug) ! 1295: log(LOG_DEBUG, "upecc, CONT: bn %d cn %d tn %d sn %d\n", ! 1296: bn, cn, tn, sn); ! 1297: #endif ! 1298: bp->b_flags &= ~B_BAD; ! 1299: if ((int)ptob(npf) >= bp->b_bcount) ! 1300: return (0); ! 1301: up->upwc = -((bp->b_bcount - (int)ptob(npf)) / sizeof(short)); ! 1302: break; ! 1303: } ! 1304: if (up->upwc == 0) { ! 1305: um->um_tab.b_active = 0; /* retry */ ! 1306: return (0); ! 1307: } ! 1308: /* ! 1309: * Have to continue the transfer... clear the drive, ! 1310: * and compute the position where the transfer is to continue. ! 1311: * We have completed npf+1 sectors of the transfer already; ! 1312: * restart at offset o of next sector (i.e. in UBA register reg+1). ! 1313: */ ! 1314: #ifdef notdef ! 1315: up->uper1 = 0; ! 1316: up->upcs1 |= UP_GO; ! 1317: #else ! 1318: up->upcs1 = UP_TRE|UP_IE|UP_DCLR|UP_GO; ! 1319: up->updc = cn; ! 1320: up->upda = (tn << 8) | sn; ! 1321: ubaddr = (int)ptob(reg) + o; ! 1322: up->upba = ubaddr; ! 1323: cmd = (ubaddr >> 8) & 0x300; ! 1324: cmd |= ((bp->b_flags&B_READ)?UP_RCOM:UP_WCOM)|UP_IE|UP_GO; ! 1325: um->um_tab.b_errcnt = 0; ! 1326: up->upcs1 = cmd; ! 1327: #endif ! 1328: sc->sc_blkdone = npf; ! 1329: return (1); ! 1330: } ! 1331: ! 1332: /* ! 1333: * Reset driver after UBA init. ! 1334: * Cancel software state of all pending transfers ! 1335: * and restart all units and the controller. ! 1336: */ ! 1337: upreset(uban) ! 1338: int uban; ! 1339: { ! 1340: register struct uba_ctlr *um; ! 1341: register struct uba_device *ui; ! 1342: register sc21, unit; ! 1343: ! 1344: for (sc21 = 0; sc21 < NSC; sc21++) { ! 1345: if ((um = upminfo[sc21]) == 0 || um->um_ubanum != uban || ! 1346: um->um_alive == 0) ! 1347: continue; ! 1348: printf(" sc%d", sc21); ! 1349: um->um_tab.b_active = 0; ! 1350: um->um_tab.b_actf = um->um_tab.b_actl = 0; ! 1351: up_softc[sc21].sc_recal = 0; ! 1352: up_softc[sc21].sc_wticks = 0; ! 1353: if (um->um_ubinfo) { ! 1354: printf("<%d>", (um->um_ubinfo>>28)&0xf); ! 1355: um->um_ubinfo = 0; ! 1356: } ! 1357: ((struct updevice *)(um->um_addr))->upcs2 = UPCS2_CLR; ! 1358: for (unit = 0; unit < NUP; unit++) { ! 1359: if ((ui = updinfo[unit]) == 0) ! 1360: continue; ! 1361: if (ui->ui_alive == 0 || ui->ui_mi != um) ! 1362: continue; ! 1363: uputab[unit].b_active = 0; ! 1364: (void) upustart(ui); ! 1365: } ! 1366: (void) upstart(um); ! 1367: } ! 1368: } ! 1369: ! 1370: /* ! 1371: * Wake up every second and if an interrupt is pending ! 1372: * but nothing has happened increment a counter. ! 1373: * If nothing happens for 20 seconds, reset the UNIBUS ! 1374: * and begin anew. ! 1375: */ ! 1376: upwatch() ! 1377: { ! 1378: register struct uba_ctlr *um; ! 1379: register sc21, unit; ! 1380: register struct up_softc *sc; ! 1381: ! 1382: timeout(upwatch, (caddr_t)0, hz); ! 1383: for (sc21 = 0; sc21 < NSC; sc21++) { ! 1384: um = upminfo[sc21]; ! 1385: if (um == 0 || um->um_alive == 0) ! 1386: continue; ! 1387: sc = &up_softc[sc21]; ! 1388: if (um->um_tab.b_active == 0) { ! 1389: for (unit = 0; unit < NUP; unit++) ! 1390: if (uputab[unit].b_active && ! 1391: updinfo[unit]->ui_mi == um) ! 1392: goto active; ! 1393: sc->sc_wticks = 0; ! 1394: continue; ! 1395: } ! 1396: active: ! 1397: sc->sc_wticks++; ! 1398: if (sc->sc_wticks >= 20) { ! 1399: sc->sc_wticks = 0; ! 1400: printf("sc%d: lost interrupt\n", sc21); ! 1401: ubareset(um->um_ubanum); ! 1402: } ! 1403: } ! 1404: } ! 1405: ! 1406: #define DBSIZE 20 ! 1407: ! 1408: updump(dev) ! 1409: dev_t dev; ! 1410: { ! 1411: struct updevice *upaddr; ! 1412: char *start; ! 1413: int num, blk, unit; ! 1414: struct size *sizes; ! 1415: register struct uba_regs *uba; ! 1416: register struct uba_device *ui; ! 1417: register short *rp; ! 1418: struct upst *st; ! 1419: register int retry; ! 1420: register struct disklabel *lp; ! 1421: ! 1422: unit = upunit(dev); ! 1423: if (unit >= NUP) ! 1424: return (ENXIO); ! 1425: #define phys(cast, addr) ((cast)((int)addr & 0x7fffffff)) ! 1426: ui = phys(struct uba_device *, updinfo[unit]); ! 1427: if (ui == 0 || ui->ui_alive == 0) ! 1428: return (ENXIO); ! 1429: uba = phys(struct uba_hd *, ui->ui_hd)->uh_physuba; ! 1430: ubainit(uba); ! 1431: upaddr = (struct updevice *)ui->ui_physaddr; ! 1432: DELAY(5000000); ! 1433: num = maxfree; ! 1434: upaddr->upcs2 = unit; ! 1435: DELAY(100); ! 1436: upaddr->upcs1 = UP_DCLR|UP_GO; ! 1437: upaddr->upcs1 = UP_PRESET|UP_GO; ! 1438: upaddr->upof = UPOF_FMT22; ! 1439: retry = 0; ! 1440: do { ! 1441: DELAY(25); ! 1442: if (++retry > 527) ! 1443: break; ! 1444: } while ((upaddr->upds & UP_RDY) == 0); ! 1445: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) ! 1446: return (EFAULT); ! 1447: start = 0; ! 1448: if (dumplo < 0) ! 1449: return (EINVAL); ! 1450: lp = &uplabel[unit]; ! 1451: /* should check uupart(dev) < lp->p_npartitions ? */ ! 1452: if (dumplo + num >= lp->d_partitions[uppart(dev)].p_size) ! 1453: num = lp->d_partitions[uppart(dev)].p_size - dumplo; ! 1454: while (num > 0) { ! 1455: register struct pte *io; ! 1456: register int i; ! 1457: int blk, cn, sn, tn; ! 1458: daddr_t bn; ! 1459: ! 1460: blk = num > DBSIZE ? DBSIZE : num; ! 1461: io = uba->uba_map; ! 1462: for (i = 0; i < blk; i++) ! 1463: *(int *)io++ = (btop(start)+i) | (1<<21) | UBAMR_MRV; ! 1464: *(int *)io = 0; ! 1465: bn = dumplo + btop(start); ! 1466: cn = (bn + lp->d_partitions[hppart(dev)].p_offset) / ! 1467: lp->d_secpercyl; ! 1468: sn = bn % lp->d_secpercyl; ! 1469: tn = sn / lp->d_nsectors; ! 1470: sn = sn % lp->d_nsectors; ! 1471: upaddr->updc = cn; ! 1472: rp = (short *) &upaddr->upda; ! 1473: *rp = (tn << 8) + sn; ! 1474: *--rp = 0; ! 1475: *--rp = -blk*NBPG / sizeof (short); ! 1476: *--rp = UP_GO|UP_WCOM; ! 1477: retry = 0; ! 1478: do { ! 1479: DELAY(25); ! 1480: if (++retry > 527) ! 1481: break; ! 1482: } while ((upaddr->upcs1 & UP_RDY) == 0); ! 1483: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 1484: printf("up%d: not ready", unit); ! 1485: if ((upaddr->upds & UPDS_DREADY) != UPDS_DREADY) { ! 1486: printf("\n"); ! 1487: return (EIO); ! 1488: } ! 1489: printf(" (flakey)\n"); ! 1490: } ! 1491: if (upaddr->upds&UPDS_ERR) ! 1492: return (EIO); ! 1493: start += blk*NBPG; ! 1494: num -= blk; ! 1495: } ! 1496: return (0); ! 1497: } ! 1498: ! 1499: upsize(dev) ! 1500: dev_t dev; ! 1501: { ! 1502: register int unit = upunit(dev); ! 1503: struct uba_device *ui; ! 1504: ! 1505: if (unit >= NUP || (ui = updinfo[unit]) == 0 || ui->ui_alive == 0 || ! 1506: upsoftc[unit].sc_state != OPEN) ! 1507: return (-1); ! 1508: return ((int)uplabel[unit].d_partitions[uppart(dev)].p_size); ! 1509: } ! 1510: ! 1511: #ifdef COMPAT_42 ! 1512: /* ! 1513: * Compatibility code to fake up pack label ! 1514: * for unlabeled disks. ! 1515: */ ! 1516: struct size { ! 1517: daddr_t nblocks; ! 1518: int cyloff; ! 1519: } up9300_sizes[8] = { ! 1520: 15884, 0, /* A=cyl 0 thru 26 */ ! 1521: 33440, 27, /* B=cyl 27 thru 81 */ ! 1522: 495520, 0, /* C=cyl 0 thru 814 */ ! 1523: 15884, 562, /* D=cyl 562 thru 588 */ ! 1524: 55936, 589, /* E=cyl 589 thru 680 */ ! 1525: 81376, 681, /* F=cyl 681 thru 814 */ ! 1526: 153728, 562, /* G=cyl 562 thru 814 */ ! 1527: 291346, 82, /* H=cyl 82 thru 561 */ ! 1528: }, up9766_sizes[8] = { ! 1529: 15884, 0, /* A=cyl 0 thru 26 */ ! 1530: 33440, 27, /* B=cyl 27 thru 81 */ ! 1531: 500384, 0, /* C=cyl 0 thru 822 */ ! 1532: 15884, 562, /* D=cyl 562 thru 588 */ ! 1533: 55936, 589, /* E=cyl 589 thru 680 */ ! 1534: 86240, 681, /* F=cyl 681 thru 822 */ ! 1535: 158592, 562, /* G=cyl 562 thru 822 */ ! 1536: 291346, 82, /* H=cyl 82 thru 561 */ ! 1537: }, up160_sizes[8] = { ! 1538: 15884, 0, /* A=cyl 0 thru 49 */ ! 1539: 33440, 50, /* B=cyl 50 thru 154 */ ! 1540: 263360, 0, /* C=cyl 0 thru 822 */ ! 1541: 15884, 155, /* D=cyl 155 thru 204 */ ! 1542: 55936, 205, /* E=cyl 205 thru 379 */ ! 1543: 141664, 380, /* F=cyl 380 thru 822 */ ! 1544: 213664, 155, /* G=cyl 155 thru 822 */ ! 1545: 0, 0, ! 1546: }, upam_sizes[8] = { ! 1547: 15884, 0, /* A=cyl 0 thru 31 */ ! 1548: 33440, 32, /* B=cyl 32 thru 97 */ ! 1549: 524288, 0, /* C=cyl 0 thru 1023 */ ! 1550: 15884, 668, /* D=cyl 668 thru 699 */ ! 1551: 55936, 700, /* E=cyl 700 thru 809 */ ! 1552: 109472, 810, /* F=cyl 810 thru 1023 */ ! 1553: 182176, 668, /* G=cyl 668 thru 1023 */ ! 1554: 291346, 98, /* H=cyl 98 thru 667 */ ! 1555: }, up980_sizes[8] = { ! 1556: 15884, 0, /* A=cyl 0 thru 99 */ ! 1557: 33440, 100, /* B=cyl 100 thru 308 */ ! 1558: 131680, 0, /* C=cyl 0 thru 822 */ ! 1559: 15884, 309, /* D=cyl 309 thru 408 */ ! 1560: 55936, 409, /* E=cyl 409 thru 758 */ ! 1561: 10080, 759, /* F=cyl 759 thru 822 */ ! 1562: 82080, 309, /* G=cyl 309 thru 822 */ ! 1563: 0, 0, ! 1564: }, upeagle_sizes[8] = { ! 1565: 15884, 0, /* A=cyl 0 thru 16 */ ! 1566: 66880, 17, /* B=cyl 17 thru 86 */ ! 1567: 808320, 0, /* C=cyl 0 thru 841 */ ! 1568: 15884, 391, /* D=cyl 391 thru 407 */ ! 1569: 307200, 408, /* E=cyl 408 thru 727 */ ! 1570: 109296, 728, /* F=cyl 728 thru 841 */ ! 1571: 432816, 391, /* G=cyl 391 thru 841 */ ! 1572: 291346, 87, /* H=cyl 87 thru 390 */ ! 1573: }; ! 1574: ! 1575: struct upst { ! 1576: short nsect; /* # sectors/track */ ! 1577: short ntrak; /* # tracks/cylinder */ ! 1578: short nspc; /* # sectors/cylinder */ ! 1579: short ncyl; /* # cylinders */ ! 1580: struct size *sizes; /* partition tables */ ! 1581: short sdist; /* seek distance metric */ ! 1582: short rdist; /* rotational distance metric */ ! 1583: short mdist; /* min rotation (all guesswork) */ ! 1584: } upst[] = { ! 1585: { 32, 19, 32*19, 815, up9300_sizes, 3, 4, 1 }, /*9300*/ ! 1586: { 32, 19, 32*19, 823, up9766_sizes, 3, 4, 1 }, /*9766*/ ! 1587: { 32, 10, 32*10, 823, up160_sizes, 3, 4, 1 }, /*fuji160m*/ ! 1588: { 32, 16, 32*16, 1024, upam_sizes, 7, 8, 2 }, /*Capricorn*/ ! 1589: { 32, 5, 32*5, 823, up980_sizes, 3, 4, 1 }, /*DM980*/ ! 1590: { 48, 20, 48*20, 842, upeagle_sizes, 15, 8, 3 }, /*EAGLE*/ ! 1591: { 0, 0, 0, 0, 0, 0, 0, 0 } ! 1592: }; ! 1593: ! 1594: ! 1595: /* ! 1596: * These variable are all measured in sectors. ! 1597: * Sdist is how much to "lead" in the search for a desired sector ! 1598: * (i.e. if want N, search for N-sdist.) ! 1599: * Maxdist and mindist define the region right before our desired sector within ! 1600: * which we don't bother searching. We don't search when we are already less ! 1601: * then maxdist and more than mindist sectors "before" our desired sector. ! 1602: * Maxdist should be >= sdist. ! 1603: * ! 1604: * Beware, sdist, mindist and maxdist are not well tuned ! 1605: * for many of the drives listed in this table. ! 1606: * Try patching things with something i/o intensive ! 1607: * running and watch iostat. ! 1608: */ ! 1609: ! 1610: /* ! 1611: * Map apparent SC[23]1 drive type into manufacturer ! 1612: * specific configuration. ! 1613: */ ! 1614: upmaptype(ui, lp) ! 1615: register struct uba_device *ui; ! 1616: register struct disklabel *lp; ! 1617: { ! 1618: register int type; ! 1619: register struct upst *st; ! 1620: ! 1621: upphysical(ui->ui_addr, lp); /* get the real drive numbers */ ! 1622: for (st = upst, type = 0; st->nsect != 0; st++, type++) ! 1623: if (lp->d_ntracks == st->ntrak && ! 1624: lp->d_nsectors == st->nsect && ! 1625: lp->d_ncylinders == st->ncyl) ! 1626: break; ! 1627: ! 1628: if (st->nsect == 0) { ! 1629: printf(": %dx%dx%d (s,t,c)?", lp->d_nsectors, ! 1630: lp->d_ntracks, lp->d_ncylinders); ! 1631: return (0); ! 1632: } ! 1633: ! 1634: ui->ui_type = type; ! 1635: ! 1636: /* ! 1637: * set up minimal disk label. ! 1638: */ ! 1639: st = &hpst[type]; ! 1640: lp->d_secsize = 512; ! 1641: lp->d_nsectors = st->nsect; ! 1642: lp->d_ntracks = st->ntrak; ! 1643: lp->d_secpercyl = st->nspc; ! 1644: lp->d_ncylinders = st->ncyl; ! 1645: lp->d_secperunit = st->nspc * st->ncyl; ! 1646: lp->d_sdist = st->sdist; ! 1647: lp->d_mindist = st->rdist; ! 1648: lp->d_maxdist = st->mdist; ! 1649: bcopy(hpst[type].name, lp->d_typename, sizeof(lp->d_typename)); ! 1650: lp->d_npartitions = 8; ! 1651: for (i = 0; i < 8; i++) { ! 1652: lp->d_partitions[i].p_offset = st->sizes[i].cyloff * ! 1653: lp->d_secpercyl; ! 1654: lp->d_partitions[i].p_size = st->sizes[i].nblocks; ! 1655: } ! 1656: return (1); ! 1657: } ! 1658: #endif /* COMPAT_42 */ ! 1659: ! 1660: #endif /* NSC > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.