|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Harris Corp. ! 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: * @(#)hd.c 7.11 (Berkeley) 6/28/90 ! 24: */ ! 25: ! 26: #include "hd.h" ! 27: ! 28: #if NHD > 0 ! 29: #include "param.h" ! 30: #include "buf.h" ! 31: #include "conf.h" ! 32: #include "dkstat.h" ! 33: #include "disklabel.h" ! 34: #include "file.h" ! 35: #include "systm.h" ! 36: #include "vmmac.h" ! 37: #include "time.h" ! 38: #include "proc.h" ! 39: #include "uio.h" ! 40: #include "syslog.h" ! 41: #include "kernel.h" ! 42: #include "ioctl.h" ! 43: #include "stat.h" ! 44: #include "errno.h" ! 45: ! 46: #include "../tahoe/cpu.h" ! 47: #include "../tahoe/mtpr.h" ! 48: ! 49: #include "../tahoevba/vbavar.h" ! 50: #include "../tahoevba/hdreg.h" ! 51: ! 52: #define b_cylin b_resid ! 53: ! 54: #define hdunit(dev) (minor(dev)>>3) ! 55: #define hdpart(dev) (minor(dev)&0x07) ! 56: #define hdminor(unit, part) (((unit)<<3)|(part)) ! 57: ! 58: struct vba_ctlr *hdcminfo[NHDC]; ! 59: struct vba_device *hddinfo[NHD]; ! 60: int hdcprobe(), hdslave(), hdattach(), hddgo(), hdstrategy(); ! 61: long hdstd[] = { 0 }; ! 62: struct vba_driver hdcdriver = ! 63: { hdcprobe, hdslave, hdattach, hddgo, hdstd, "hd", hddinfo, "hdc", hdcminfo }; ! 64: ! 65: /* ! 66: * Per-controller state. ! 67: */ ! 68: struct hdcsoftc { ! 69: u_short hdc_flags; ! 70: #define HDC_INIT 0x01 /* controller initialized */ ! 71: #define HDC_STARTED 0x02 /* start command issued */ ! 72: #define HDC_LOCKED 0x04 /* locked for direct controller access */ ! 73: #define HDC_WAIT 0x08 /* someone needs direct controller access */ ! 74: u_short hdc_wticks; /* timeout */ ! 75: struct master_mcb *hdc_mcbp; /* address of controller mcb */ ! 76: struct registers *hdc_reg; /* base address of i/o regs */ ! 77: struct vb_buf hdc_rbuf; /* vba resources */ ! 78: struct master_mcb hdc_mcb; /* controller mcb */ ! 79: } hdcsoftc[NHDC]; ! 80: ! 81: #define HDCMAXTIME 20 /* max time for operation, sec. */ ! 82: #define HDCINTERRUPT 0xf0 /* interrupt vector */ ! 83: ! 84: /* ! 85: * Per-drive state; probably everything should be "hd_", not "dk_", ! 86: * but it's not worth it, and dk is a better mnemonic for disk anyway. ! 87: */ ! 88: struct dksoftc { ! 89: #ifdef COMPAT_42 ! 90: u_short dk_def_cyl; /* definition track cylinder address */ ! 91: #endif ! 92: int dk_state; /* open fsm */ ! 93: u_short dk_bshift; /* shift for * (DEV_BSIZE / sectorsize) XXX */ ! 94: int dk_wlabel; /* if label sector is writeable */ ! 95: u_long dk_copenpart; /* character units open on this drive */ ! 96: u_long dk_bopenpart; /* block units open on this drive */ ! 97: u_long dk_openpart; /* all units open on this drive */ ! 98: int dk_unit; /* unit# */ ! 99: int dk_ctlr; /* controller# */ ! 100: int dk_format; /* if format program is using disk */ ! 101: struct buf dk_utab; /* i/o queue header */ ! 102: struct disklabel dk_label; /* disklabel for this disk */ ! 103: struct mcb dk_mcb; /* disk mcb */ ! 104: } dksoftc[NHD]; ! 105: ! 106: /* ! 107: * Drive states. Used during steps of open/initialization. ! 108: * States < OPEN (> 0) are transient, during an open operation. ! 109: * OPENRAW is used for unlabeled disks, to allow format operations. ! 110: */ ! 111: #define CLOSED 0 /* disk is closed */ ! 112: #define WANTOPEN 1 /* open requested, not started */ ! 113: #define WANTOPENRAW 2 /* open requested, no label */ ! 114: #define RDLABEL 3 /* reading pack label */ ! 115: #define OPEN 4 /* intialized and ready */ ! 116: #define OPENRAW 5 /* open, no label */ ! 117: ! 118: int hdcwstart, hdcwatch(); ! 119: ! 120: /* see if the controller is really there, if so, init it. */ ! 121: /* ARGSUSED */ ! 122: hdcprobe(reg, vm) ! 123: caddr_t reg; ! 124: /* register */ struct vba_ctlr *vm; ! 125: { ! 126: register int br, cvec; /* must be r12, r11 */ ! 127: register struct hdcsoftc *hdc; ! 128: static struct module_id id; ! 129: struct pte *dummypte; ! 130: caddr_t putl; ! 131: ! 132: /* initialize the hdc controller structure. */ ! 133: hdc = &hdcsoftc[vm->um_ctlr]; ! 134: if (!vbmemalloc(1, reg, &dummypte, &putl)) { ! 135: printf("hdc%d: vbmemalloc failed.\n", vm->um_ctlr); ! 136: return(0); ! 137: } ! 138: hdc->hdc_reg = (struct registers *)putl; ! 139: ! 140: /* ! 141: * try and ping the MID register; side effect of wbadaddr is to read ! 142: * the module id; the controller is bad if it's not an hdc, the hdc's ! 143: * writeable control store is not loaded, or the hdc failed the ! 144: * functional integrity test; ! 145: */ ! 146: if (wbadaddr(&hdc->hdc_reg->module_id, 4, ! 147: vtoph((struct process *)NULL, &id))) ! 148: return(0); ! 149: DELAY(10000); ! 150: mtpr(PADC, 0); ! 151: if (id.module_id != (u_char)HDC_MID) { ! 152: printf("hdc%d: bad module id; id = %x.\n", ! 153: vm->um_ctlr, id.module_id); ! 154: return(0); ! 155: } ! 156: if (id.code_rev == (u_char)0xff) { ! 157: printf("hdc%d: micro-code not loaded.\n", vm->um_ctlr); ! 158: return(0); ! 159: } ! 160: if (id.fit != (u_char)0xff) { ! 161: printf("hdc%d: FIT test failed.\n", vm->um_ctlr); ! 162: return(0); ! 163: } ! 164: ! 165: /* reset that pup; flag as inited */ ! 166: hdc->hdc_reg->soft_reset = 0; ! 167: DELAY(1000000); ! 168: hdc->hdc_flags |= HDC_INIT; ! 169: ! 170: /* allocate page tables and i/o buffer. */ ! 171: if (!vbainit(&hdc->hdc_rbuf, MAXPHYS, VB_32BIT|VB_SCATTER)) { ! 172: printf("hdc%d: vbainit failed\n", vm->um_ctlr); ! 173: return (0); ! 174: } ! 175: ! 176: /* set pointer to master control block */ ! 177: hdc->hdc_mcbp = ! 178: (struct master_mcb *)vtoph((struct proc *)NULL, &hdc->hdc_mcb); ! 179: ! 180: br = 0x17, cvec = HDCINTERRUPT + vm->um_ctlr; /* XXX */ ! 181: return(sizeof(struct registers)); ! 182: } ! 183: ! 184: /* ARGSUSED */ ! 185: hdslave(vi, vdaddr) ! 186: struct vba_device *vi; ! 187: struct vddevice *vdaddr; ! 188: { ! 189: register struct mcb *mcb; ! 190: register struct disklabel *lp; ! 191: register struct dksoftc *dk; ! 192: static struct status status; ! 193: ! 194: dk = &dksoftc[vi->ui_unit]; ! 195: dk->dk_unit = vi->ui_unit; ! 196: dk->dk_ctlr = vi->ui_ctlr; ! 197: ! 198: mcb = &dk->dk_mcb; ! 199: mcb->command = HCMD_STATUS; ! 200: mcb->chain[0].wcount = sizeof(struct status) / sizeof(long); ! 201: mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &status); ! 202: if (hdimcb(dk)) { ! 203: printf(" (no status)\n"); ! 204: return(0); ! 205: } ! 206: ! 207: /* ! 208: * Report the drive down if anything in the drive status looks bad. ! 209: * If the drive is offline and it is not on cylinder, then the drive ! 210: * is not there. If there is a fault condition, the hdc will try to ! 211: * clear it when we read the disklabel information. ! 212: */ ! 213: if (!(status.drs&DRS_ONLINE)) { ! 214: if (status.drs&DRS_ON_CYLINDER) ! 215: printf(" (not online)\n"); ! 216: return(0); ! 217: } ! 218: if (status.drs&DRS_FAULT) ! 219: printf(" (clearing fault)"); ! 220: ! 221: lp = &dk->dk_label; ! 222: #ifdef RAW_SIZE ! 223: lp->d_secsize = status.bytes_per_sec; ! 224: #else ! 225: lp->d_secsize = 512; ! 226: #endif ! 227: lp->d_nsectors = status.max_sector + 1; ! 228: lp->d_ntracks = status.max_head + 1; ! 229: lp->d_ncylinders = status.max_cyl + 1; ! 230: lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; ! 231: lp->d_npartitions = 1; ! 232: lp->d_partitions[0].p_offset = 0; ! 233: lp->d_partitions[0].p_size = LABELSECTOR + 1; ! 234: lp->d_rpm = status.rpm; ! 235: lp->d_typename[0] = 'h'; ! 236: lp->d_typename[1] = 'd'; ! 237: lp->d_typename[2] = '\0'; ! 238: #ifdef COMPAT_42 ! 239: dk->dk_def_cyl = status.def_cyl; ! 240: #endif ! 241: return(1); ! 242: } ! 243: ! 244: hdattach(vi) ! 245: register struct vba_device *vi; ! 246: { ! 247: register struct dksoftc *dk; ! 248: register struct disklabel *lp; ! 249: register int unit; ! 250: ! 251: unit = vi->ui_unit; ! 252: if (hdinit(hdminor(unit, 0), 0)) { ! 253: printf(": unknown drive type"); ! 254: return; ! 255: } ! 256: dk = &dksoftc[unit]; ! 257: lp = &dk->dk_label; ! 258: hd_setsecsize(dk, lp); ! 259: if (dk->dk_state == OPEN) ! 260: printf(": %s <secsize %d, ntrak %d, ncyl %d, nsec %d>", ! 261: lp->d_typename, lp->d_secsize, lp->d_ntracks, ! 262: lp->d_ncylinders, lp->d_nsectors); ! 263: ! 264: /* ! 265: * (60 / rpm) / (sectors per track * (bytes per sector / 2)) ! 266: */ ! 267: if (vi->ui_dk >= 0) ! 268: dk_wpms[vi->ui_dk] = ! 269: (lp->d_rpm * lp->d_nsectors * lp->d_secsize) / 120; ! 270: #ifdef notyet ! 271: addswap(makedev(HDMAJOR, hdminor(unit, 0)), lp); ! 272: #endif ! 273: } ! 274: ! 275: hdopen(dev, flags, fmt) ! 276: dev_t dev; ! 277: int flags, fmt; ! 278: { ! 279: register struct disklabel *lp; ! 280: register struct dksoftc *dk; ! 281: register struct partition *pp; ! 282: register int unit; ! 283: struct vba_device *vi; ! 284: int s, error, part = hdpart(dev), mask = 1 << part; ! 285: daddr_t start, end; ! 286: ! 287: unit = hdunit(dev); ! 288: if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0) ! 289: return(ENXIO); ! 290: dk = &dksoftc[unit]; ! 291: lp = &dk->dk_label; ! 292: s = spl7(); ! 293: while (dk->dk_state != OPEN && dk->dk_state != OPENRAW && ! 294: dk->dk_state != CLOSED) ! 295: if (error = tsleep((caddr_t)dk, (PZERO+1) | PCATCH, ! 296: devopn, 0)) { ! 297: splx(s); ! 298: return (error); ! 299: } ! 300: splx(s); ! 301: if (dk->dk_state != OPEN && dk->dk_state != OPENRAW) ! 302: if (error = hdinit(dev, flags)) ! 303: return(error); ! 304: ! 305: if (hdcwstart == 0) { ! 306: timeout(hdcwatch, (caddr_t)0, hz); ! 307: hdcwstart++; ! 308: } ! 309: /* ! 310: * Warn if a partion is opened that overlaps another partition ! 311: * which is open unless one is the "raw" partition (whole disk). ! 312: */ ! 313: #define RAWPART 8 /* 'x' partition */ /* XXX */ ! 314: if ((dk->dk_openpart & mask) == 0 && part != RAWPART) { ! 315: pp = &lp->d_partitions[part]; ! 316: start = pp->p_offset; ! 317: end = pp->p_offset + pp->p_size; ! 318: for (pp = lp->d_partitions; ! 319: pp < &lp->d_partitions[lp->d_npartitions]; pp++) { ! 320: if (pp->p_offset + pp->p_size <= start || ! 321: pp->p_offset >= end) ! 322: continue; ! 323: if (pp - lp->d_partitions == RAWPART) ! 324: continue; ! 325: if (dk->dk_openpart & (1 << (pp - lp->d_partitions))) ! 326: log(LOG_WARNING, ! 327: "hd%d%c: overlaps open partition (%c)\n", ! 328: unit, part + 'a', ! 329: pp - lp->d_partitions + 'a'); ! 330: } ! 331: } ! 332: if (part >= lp->d_npartitions) ! 333: return(ENXIO); ! 334: dk->dk_openpart |= mask; ! 335: switch (fmt) { ! 336: case S_IFCHR: ! 337: dk->dk_copenpart |= mask; ! 338: break; ! 339: case S_IFBLK: ! 340: dk->dk_bopenpart |= mask; ! 341: break; ! 342: } ! 343: return(0); ! 344: } ! 345: ! 346: /* ARGSUSED */ ! 347: hdclose(dev, flags, fmt) ! 348: dev_t dev; ! 349: int flags, fmt; ! 350: { ! 351: register struct dksoftc *dk; ! 352: int mask; ! 353: ! 354: dk = &dksoftc[hdunit(dev)]; ! 355: mask = 1 << hdpart(dev); ! 356: switch (fmt) { ! 357: case S_IFCHR: ! 358: dk->dk_copenpart &= ~mask; ! 359: break; ! 360: case S_IFBLK: ! 361: dk->dk_bopenpart &= ~mask; ! 362: break; ! 363: } ! 364: if (((dk->dk_copenpart | dk->dk_bopenpart) & mask) == 0) ! 365: dk->dk_openpart &= ~mask; ! 366: /* ! 367: * Should wait for i/o to complete on this partition ! 368: * even if others are open, but wait for work on blkflush(). ! 369: */ ! 370: if (dk->dk_openpart == 0) { ! 371: int s = spl7(); ! 372: while (dk->dk_utab.b_actf) ! 373: sleep((caddr_t)dk, PZERO-1); ! 374: splx(s); ! 375: dk->dk_state = CLOSED; ! 376: dk->dk_wlabel = 0; ! 377: } ! 378: return(0); ! 379: } ! 380: ! 381: hdinit(dev, flags) ! 382: dev_t dev; ! 383: int flags; ! 384: { ! 385: register struct dksoftc *dk; ! 386: register struct disklabel *lp; ! 387: struct vba_device *vi; ! 388: int error, unit; ! 389: char *msg, *readdisklabel(); ! 390: extern int cold; ! 391: ! 392: vi = hddinfo[unit = hdunit(dev)]; ! 393: dk = &dksoftc[unit]; ! 394: dk->dk_unit = vi->ui_slave; ! 395: dk->dk_ctlr = vi->ui_ctlr; ! 396: ! 397: if (flags & O_NDELAY) { ! 398: dk->dk_state = OPENRAW; ! 399: return(0); ! 400: } ! 401: ! 402: error = 0; ! 403: lp = &dk->dk_label; ! 404: dk->dk_state = RDLABEL; ! 405: if (msg = readdisklabel(dev, hdstrategy, lp)) { ! 406: if (cold) { ! 407: printf(": %s\n", msg); ! 408: dk->dk_state = CLOSED; ! 409: } else { ! 410: log(LOG_ERR, "hd%d: %s\n", unit, msg); ! 411: dk->dk_state = OPENRAW; ! 412: } ! 413: #ifdef COMPAT_42 ! 414: hdclock(vi->ui_ctlr); ! 415: if (!(error = hdreadgeometry(dk))) ! 416: dk->dk_state = OPEN; ! 417: hdcunlock(vi->ui_ctlr); ! 418: #endif ! 419: } else ! 420: dk->dk_state = OPEN; ! 421: wakeup((caddr_t)dk); ! 422: return(error); ! 423: } ! 424: ! 425: hd_setsecsize(dk, lp) ! 426: register struct dksoftc *dk; ! 427: struct disklabel *lp; ! 428: { ! 429: register int mul; ! 430: ! 431: /* ! 432: * Calculate scaling shift for mapping ! 433: * DEV_BSIZE blocks to drive sectors. ! 434: */ ! 435: mul = DEV_BSIZE / lp->d_secsize; ! 436: dk->dk_bshift = 0; ! 437: while ((mul >>= 1) > 0) ! 438: dk->dk_bshift++; ! 439: } ! 440: ! 441: /* ARGSUSED */ ! 442: hddgo(vm) ! 443: struct vba_device *vm; ! 444: {} ! 445: ! 446: extern int name_ext; ! 447: hdstrategy(bp) ! 448: register struct buf *bp; ! 449: { ! 450: register struct vba_device *vi; ! 451: register struct disklabel *lp; ! 452: register struct dksoftc *dk; ! 453: struct buf *dp; ! 454: register int unit; ! 455: daddr_t sn, sz, maxsz; ! 456: int part, s; ! 457: ! 458: vi = hddinfo[unit = hdunit(bp->b_dev)]; ! 459: if (unit >= NHD || vi == 0 || vi->ui_alive == 0) { ! 460: bp->b_error = ENXIO; ! 461: goto bad; ! 462: } ! 463: dk = &dksoftc[unit]; ! 464: if (dk->dk_state < OPEN) ! 465: goto q; ! 466: if (dk->dk_state != OPEN && (bp->b_flags & B_READ) == 0) { ! 467: bp->b_error = EROFS; ! 468: goto bad; ! 469: } ! 470: part = hdpart(bp->b_dev); ! 471: if ((dk->dk_openpart & (1 << part)) == 0) { ! 472: bp->b_error = ENODEV; ! 473: goto bad; ! 474: } ! 475: lp = &dk->dk_label; ! 476: sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; ! 477: maxsz = lp->d_partitions[part].p_size; ! 478: sn = bp->b_blkno << dk->dk_bshift; ! 479: if (sn + lp->d_partitions[part].p_offset <= LABELSECTOR && ! 480: #if LABELSECTOR != 0 ! 481: sn + lp->d_partitions[part].p_offset + sz > LABELSECTOR && ! 482: #endif ! 483: (bp->b_flags & B_READ) == 0 && dk->dk_wlabel == 0) { ! 484: bp->b_error = EROFS; ! 485: goto bad; ! 486: } ! 487: if (sn < 0 || sn + sz > maxsz) { ! 488: if (sn == maxsz) { ! 489: bp->b_resid = bp->b_bcount; ! 490: goto done; ! 491: } ! 492: sz = maxsz - sn; ! 493: if (sz <= 0) { ! 494: bp->b_error = EINVAL; ! 495: goto bad; ! 496: } ! 497: bp->b_bcount = sz * lp->d_secsize; ! 498: } ! 499: bp->b_cylin = (sn + lp->d_partitions[part].p_offset) / lp->d_secpercyl; ! 500: ! 501: q: s = spl7(); ! 502: dp = &dk->dk_utab; ! 503: disksort(dp, bp); ! 504: if (!dp->b_active) { ! 505: (void)hdustart(vi); ! 506: if (!vi->ui_mi->um_tab.b_active) ! 507: hdcstart(vi->ui_mi); ! 508: } ! 509: splx(s); ! 510: return; ! 511: bad: ! 512: bp->b_flags |= B_ERROR; ! 513: done: ! 514: biodone(bp); ! 515: } ! 516: ! 517: hdustart(vi) ! 518: register struct vba_device *vi; ! 519: { ! 520: register struct buf *bp, *dp; ! 521: register struct vba_ctlr *vm; ! 522: register struct dksoftc *dk; ! 523: ! 524: dk = &dksoftc[vi->ui_unit]; ! 525: dp = &dk->dk_utab; ! 526: ! 527: /* if queue empty, nothing to do. impossible? */ ! 528: if (dp->b_actf == NULL) ! 529: return; ! 530: ! 531: /* place on controller transfer queue */ ! 532: vm = vi->ui_mi; ! 533: if (vm->um_tab.b_actf == NULL) ! 534: vm->um_tab.b_actf = dp; ! 535: else ! 536: vm->um_tab.b_actl->b_forw = dp; ! 537: vm->um_tab.b_actl = dp; ! 538: dp->b_forw = NULL; ! 539: dp->b_active++; ! 540: } ! 541: ! 542: hdcstart(vm) ! 543: register struct vba_ctlr *vm; ! 544: { ! 545: register struct buf *bp; ! 546: register struct dksoftc *dk; ! 547: register struct disklabel *lp; ! 548: register struct master_mcb *master; ! 549: register struct mcb *mcb; ! 550: struct vba_device *vi; ! 551: struct hdcsoftc *hdc; ! 552: struct buf *dp; ! 553: int sn; ! 554: ! 555: /* pull a request off the controller queue */ ! 556: for (;;) { ! 557: if ((dp = vm->um_tab.b_actf) == NULL) ! 558: return; ! 559: if (bp = dp->b_actf) ! 560: break; ! 561: vm->um_tab.b_actf = dp->b_forw; ! 562: } ! 563: ! 564: /* mark controller active */ ! 565: vm->um_tab.b_active++; ! 566: ! 567: vi = hddinfo[hdunit(bp->b_dev)]; ! 568: dk = &dksoftc[vi->ui_unit]; ! 569: lp = &dk->dk_label; ! 570: sn = bp->b_blkno << dk->dk_bshift; ! 571: ! 572: /* fill in mcb */ ! 573: mcb = &dk->dk_mcb; ! 574: mcb->forw_phaddr = 0; ! 575: /* mcb->priority = 0; */ ! 576: mcb->interrupt = 1; ! 577: mcb->command = (bp->b_flags & B_READ) ? HCMD_READ:HCMD_WRITE; ! 578: mcb->cyl = bp->b_cylin; ! 579: /* assumes partition starts on cylinder boundary */ ! 580: mcb->head = (sn / lp->d_nsectors) % lp->d_ntracks; ! 581: mcb->sector = sn % lp->d_nsectors; ! 582: mcb->drive = vi->ui_slave; ! 583: /* mcb->context = 0; /* what do we want on interrupt? */ ! 584: ! 585: hdc = &hdcsoftc[vm->um_ctlr]; ! 586: if (!hd_sgsetup(bp, &hdc->hdc_rbuf, mcb->chain)) { ! 587: mcb->chain[0].wcount = (bp->b_bcount+3) >> 2; ! 588: mcb->chain[0].memadr = ! 589: vbasetup(bp, &hdc->hdc_rbuf, (int)lp->d_secsize); ! 590: } ! 591: ! 592: if (vi->ui_dk >= 0) { ! 593: dk_busy |= 1<<vi->ui_dk; ! 594: dk_xfer[vi->ui_dk]++; ! 595: dk_wds[vi->ui_dk] += bp->b_bcount>>6; ! 596: } ! 597: ! 598: master = &hdc->hdc_mcb; ! 599: master->mcw = MCL_QUEUED; ! 600: master->interrupt = HDCINTERRUPT + vm->um_ctlr; ! 601: master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb); ! 602: hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp; ! 603: } ! 604: ! 605: /* ! 606: * Wait for controller to finish current operation ! 607: * so that direct controller accesses can be done. ! 608: */ ! 609: hdclock(ctlr) ! 610: int ctlr; ! 611: { ! 612: register struct vba_ctlr *vm = hdcminfo[ctlr]; ! 613: register struct hdcsoftc *hdc; ! 614: int s; ! 615: ! 616: hdc = &hdcsoftc[ctlr]; ! 617: s = spl7(); ! 618: while (vm->um_tab.b_active || hdc->hdc_flags & HDC_LOCKED) { ! 619: hdc->hdc_flags |= HDC_WAIT; ! 620: sleep((caddr_t)hdc, PRIBIO); ! 621: } ! 622: hdc->hdc_flags |= HDC_LOCKED; ! 623: splx(s); ! 624: } ! 625: ! 626: /* ! 627: * Continue normal operations after pausing for ! 628: * munging the controller directly. ! 629: */ ! 630: hdcunlock(ctlr) ! 631: int ctlr; ! 632: { ! 633: register struct vba_ctlr *vm; ! 634: register struct hdcsoftc *hdc = &hdcsoftc[ctlr]; ! 635: ! 636: hdc->hdc_flags &= ~HDC_LOCKED; ! 637: if (hdc->hdc_flags & HDC_WAIT) { ! 638: hdc->hdc_flags &= ~HDC_WAIT; ! 639: wakeup((caddr_t)hdc); ! 640: } else { ! 641: vm = hdcminfo[ctlr]; ! 642: if (vm->um_tab.b_actf) ! 643: hdcstart(vm); ! 644: } ! 645: } ! 646: ! 647: hdintr(ctlr) ! 648: int ctlr; ! 649: { ! 650: register struct buf *bp, *dp; ! 651: register struct vba_ctlr *vm; ! 652: register struct vba_device *vi; ! 653: register struct hdcsoftc *hdc; ! 654: register struct mcb *mcb; ! 655: struct master_mcb *master; ! 656: register int status; ! 657: int timedout; ! 658: struct dksoftc *dk; ! 659: ! 660: hdc = &hdcsoftc[ctlr]; ! 661: master = &hdc->hdc_mcb; ! 662: uncache(&master->mcs); ! 663: uncache(&master->context); ! 664: ! 665: vm = hdcminfo[ctlr]; ! 666: if (!vm->um_tab.b_active || !(master->mcs&MCS_DONE)) { ! 667: printf("hd%d: stray interrupt\n", ctlr); ! 668: return; ! 669: } ! 670: ! 671: dp = vm->um_tab.b_actf; ! 672: bp = dp->b_actf; ! 673: vi = hddinfo[hdunit(bp->b_dev)]; ! 674: dk = &dksoftc[vi->ui_unit]; ! 675: if (vi->ui_dk >= 0) ! 676: dk_busy &= ~(1<<vi->ui_dk); ! 677: timedout = (hdc->hdc_wticks >= HDCMAXTIME); ! 678: ! 679: mcb = &dk->dk_mcb; ! 680: ! 681: if (master->mcs & (MCS_SOFTERROR | MCS_FATALERROR) || timedout) ! 682: hdcerror(ctlr, *(u_long *)master->xstatus); ! 683: else ! 684: hdc->hdc_wticks = 0; ! 685: if (vm->um_tab.b_active) { ! 686: vm->um_tab.b_active = 0; ! 687: vm->um_tab.b_actf = dp->b_forw; ! 688: dp->b_active = 0; ! 689: dp->b_errcnt = 0; ! 690: dp->b_actf = bp->av_forw; ! 691: bp->b_resid = 0; ! 692: vbadone(bp, &hdc->hdc_rbuf); ! 693: biodone(bp); ! 694: /* start up now, if more work to do */ ! 695: if (dp->b_actf) ! 696: hdustart(vi); ! 697: else if (dk->dk_openpart == 0) ! 698: wakeup((caddr_t)dk); ! 699: } ! 700: /* if there are devices ready to transfer, start the controller. */ ! 701: if (hdc->hdc_flags & HDC_WAIT) { ! 702: hdc->hdc_flags &= ~HDC_WAIT; ! 703: wakeup((caddr_t)hdc); ! 704: } else if (vm->um_tab.b_actf) ! 705: hdcstart(vm); ! 706: } ! 707: ! 708: hdioctl(dev, cmd, data, flag) ! 709: dev_t dev; ! 710: int cmd, flag; ! 711: caddr_t data; ! 712: { ! 713: register int unit; ! 714: register struct dksoftc *dk; ! 715: register struct disklabel *lp; ! 716: int error; ! 717: ! 718: unit = hdunit(dev); ! 719: dk = &dksoftc[unit]; ! 720: lp = &dk->dk_label; ! 721: error = 0; ! 722: switch (cmd) { ! 723: case DIOCGDINFO: ! 724: *(struct disklabel *)data = *lp; ! 725: break; ! 726: case DIOCGPART: ! 727: ((struct partinfo *)data)->disklab = lp; ! 728: ((struct partinfo *)data)->part = ! 729: &lp->d_partitions[hdpart(dev)]; ! 730: break; ! 731: case DIOCSDINFO: ! 732: if ((flag & FWRITE) == 0) ! 733: error = EBADF; ! 734: else ! 735: error = setdisklabel(lp, (struct disklabel *)data, ! 736: (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart); ! 737: if (error == 0 && dk->dk_state == OPENRAW) ! 738: dk->dk_state = OPEN; ! 739: break; ! 740: case DIOCWLABEL: ! 741: if ((flag & FWRITE) == 0) ! 742: error = EBADF; ! 743: else ! 744: dk->dk_wlabel = *(int *)data; ! 745: break; ! 746: case DIOCWDINFO: ! 747: if ((flag & FWRITE) == 0) ! 748: error = EBADF; ! 749: else if ((error = setdisklabel(lp, (struct disklabel *)data, ! 750: (dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart)) == 0) { ! 751: int wlab; ! 752: ! 753: if (error == 0 && dk->dk_state == OPENRAW) ! 754: dk->dk_state = OPEN; ! 755: /* simulate opening partition 0 so write succeeds */ ! 756: dk->dk_openpart |= (1 << 0); /* XXX */ ! 757: wlab = dk->dk_wlabel; ! 758: dk->dk_wlabel = 1; ! 759: error = writedisklabel(dev, hdstrategy, lp); ! 760: dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart; ! 761: dk->dk_wlabel = wlab; ! 762: } ! 763: break; ! 764: default: ! 765: error = ENOTTY; ! 766: break; ! 767: } ! 768: return (error); ! 769: } ! 770: ! 771: /* ! 772: * Watch for lost interrupts. ! 773: */ ! 774: hdcwatch() ! 775: { ! 776: register struct hdcsoftc *hdc; ! 777: register struct vba_ctlr **vmp; ! 778: register int ctlr; ! 779: int s; ! 780: ! 781: timeout(hdcwatch, (caddr_t)0, hz); ! 782: for (vmp = hdcminfo, hdc = hdcsoftc, ctlr = 0; ctlr < NHDC; ! 783: ++ctlr, ++vmp, ++hdc) { ! 784: if (*vmp == 0 || (*vmp)->um_alive == 0) ! 785: continue; ! 786: s = spl7(); ! 787: if ((*vmp)->um_tab.b_active && ! 788: hdc->hdc_wticks++ >= HDCMAXTIME) { ! 789: printf("hd%d: lost interrupt\n", ctlr); ! 790: hdintr(ctlr); ! 791: } ! 792: splx(s); ! 793: } ! 794: } ! 795: ! 796: hddump(dev) ! 797: dev_t dev; ! 798: { ! 799: return(ENXIO); ! 800: } ! 801: ! 802: hdsize(dev) ! 803: dev_t dev; ! 804: { ! 805: register int unit = hdunit(dev); ! 806: register struct dksoftc *dk; ! 807: struct vba_device *vi; ! 808: struct disklabel *lp; ! 809: ! 810: if (unit >= NHD || (vi = hddinfo[unit]) == 0 || vi->ui_alive == 0 || ! 811: (dk = &dksoftc[unit])->dk_state != OPEN) ! 812: return (-1); ! 813: lp = &dk->dk_label; ! 814: return ((int)lp->d_partitions[hdpart(dev)].p_size >> dk->dk_bshift); ! 815: } ! 816: ! 817: hdimcb(dk) ! 818: register struct dksoftc *dk; ! 819: { ! 820: register struct master_mcb *master; ! 821: register struct mcb *mcb; ! 822: register struct hdcsoftc *hdc; ! 823: int timeout; ! 824: ! 825: /* fill in mcb */ ! 826: mcb = &dk->dk_mcb; ! 827: mcb->interrupt = 0; ! 828: mcb->forw_phaddr = 0; ! 829: mcb->drive = dk->dk_unit; ! 830: ! 831: hdc = &hdcsoftc[dk->dk_ctlr]; ! 832: master = &hdc->hdc_mcb; ! 833: ! 834: /* fill in master mcb */ ! 835: master->mcw = MCL_IMMEDIATE; ! 836: master->forw_phaddr = (u_long)vtoph((struct proc *)NULL, mcb); ! 837: master->mcs = 0; ! 838: ! 839: /* kick controller and wait */ ! 840: hdc->hdc_reg->master_mcb = (u_long)hdc->hdc_mcbp; ! 841: for (timeout = 15000; timeout; --timeout) { ! 842: DELAY(1000); ! 843: mtpr(PADC, 0); ! 844: if (master->mcs&MCS_FATALERROR) { ! 845: printf("hdc%d: fatal error\n", dk->dk_ctlr); ! 846: hdcerror(dk->dk_ctlr, *(u_long *)master->xstatus); ! 847: return(1); ! 848: } ! 849: if (master->mcs&MCS_DONE) ! 850: return(0); ! 851: } ! 852: printf("hdc%d: timed out\n", dk->dk_ctlr); ! 853: return(1); ! 854: } ! 855: ! 856: hdcerror(ctlr, code) ! 857: int ctlr; ! 858: u_long code; ! 859: { ! 860: printf("hd%d: error %lx\n", ctlr, code); ! 861: } ! 862: ! 863: #ifdef COMPAT_42 ! 864: hdreadgeometry(dk) ! 865: struct dksoftc *dk; ! 866: { ! 867: static geometry_sector geometry; ! 868: register struct mcb *mcb; ! 869: register struct disklabel *lp; ! 870: geometry_block *geo; ! 871: int cnt; ! 872: ! 873: /* ! 874: * Read the geometry block (at head = 0 sector = 0 of the drive ! 875: * definition cylinder), validate it (must have the correct version ! 876: * number, header, and checksum). ! 877: */ ! 878: mcb = &dk->dk_mcb; ! 879: mcb->command = HCMD_READ; ! 880: mcb->cyl = dk->dk_def_cyl; ! 881: mcb->head = 0; ! 882: mcb->sector = 0; ! 883: mcb->chain[0].wcount = sizeof(geometry_sector) / sizeof(long); ! 884: mcb->chain[0].memadr = (u_long)vtoph((struct process *)0, &geometry); ! 885: /* mcb->chain[0].memadr = (long)&geometry; */ ! 886: if (hdimcb(dk)) { ! 887: printf("hd%d: can't read default geometry.\n", dk->dk_unit); ! 888: return(1); ! 889: } ! 890: geo = &geometry.geometry_block; ! 891: if (geo->version > 64000 || geo->version < 0) { ! 892: printf("hd%d: bad default geometry version#.\n", dk->dk_unit); ! 893: return(1); ! 894: } ! 895: if (bcmp(&geo->id[0], GB_ID, GB_ID_LEN)) { ! 896: printf("hd%d: bad default geometry header.\n", dk->dk_unit); ! 897: return(1); ! 898: } ! 899: GB_CHECKSUM(geo, cnt); ! 900: if (geometry.checksum != cnt) { ! 901: printf("hd%d: bad default geometry checksum.\n", dk->dk_unit); ! 902: return(1); ! 903: } ! 904: lp = &dk->dk_label; ! 905: ! 906: /* 1K block in Harris geometry; convert to sectors for disklabels */ ! 907: for (cnt = 0; cnt < GB_MAXPART; cnt++) { ! 908: lp->d_partitions[cnt].p_offset = ! 909: geo->partition[cnt].start * (1024 / lp->d_secsize); ! 910: lp->d_partitions[cnt].p_size = ! 911: geo->partition[cnt].length * (1024 / lp->d_secsize); ! 912: } ! 913: lp->d_npartitions = GB_MAXPART; ! 914: return(0); ! 915: } ! 916: #endif /* COMPAT_42 */ ! 917: #endif /* NHD */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.