|
|
1.1 ! root 1: /*- ! 2: * Copyright (c) 1990 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * William Jolitz. ! 7: * ! 8: * Redistribution and use in source and binary forms, with or without ! 9: * modification, are permitted provided that the following conditions ! 10: * are met: ! 11: * 1. Redistributions of source code must retain the above copyright ! 12: * notice, this list of conditions and the following disclaimer. ! 13: * 2. Redistributions in binary form must reproduce the above copyright ! 14: * notice, this list of conditions and the following disclaimer in the ! 15: * documentation and/or other materials provided with the distribution. ! 16: * 3. All advertising materials mentioning features or use of this software ! 17: * must display the following acknowledgement: ! 18: * This product includes software developed by the University of ! 19: * California, Berkeley and its contributors. ! 20: * 4. Neither the name of the University nor the names of its contributors ! 21: * may be used to endorse or promote products derived from this software ! 22: * without specific prior written permission. ! 23: * ! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 34: * SUCH DAMAGE. ! 35: * ! 36: * @(#)wd.c 7.2 (Berkeley) 5/9/91 ! 37: */ ! 38: ! 39: /* TODO:peel out buffer at low ipl, ! 40: speed improvement, rewrite to clean code from garbage artifacts */ ! 41: ! 42: ! 43: #include "wd.h" ! 44: #if NWD > 0 ! 45: ! 46: #include "param.h" ! 47: #include "dkbad.h" ! 48: #include "systm.h" ! 49: #include "conf.h" ! 50: #include "file.h" ! 51: #include "stat.h" ! 52: #include "ioctl.h" ! 53: #include "disklabel.h" ! 54: #include "buf.h" ! 55: #include "uio.h" ! 56: #include "i386/isa/isa_device.h" ! 57: #include "i386/isa/icu.h" ! 58: #include "i386/isa/wdreg.h" ! 59: #include "syslog.h" ! 60: #include "vm/vm.h" ! 61: ! 62: #define RETRIES 5 /* number of retries before giving up */ ! 63: #define MAXTRANSFER 32 /* max size of transfer in page clusters */ ! 64: ! 65: #define wdctlr(dev) ((minor(dev) & 0x80) >> 7) ! 66: #define wdunit(dev) ((minor(dev) & 0x60) >> 5) ! 67: #define wdpart(dev) ((minor(dev) & 0x1f)) ! 68: ! 69: #define b_cylin b_resid /* cylinder number for doing IO to */ ! 70: /* shares an entry in the buf struct */ ! 71: ! 72: /* ! 73: * Drive states. Used for open and format operations. ! 74: * States < OPEN (> 0) are transient, during an open operation. ! 75: * OPENRAW is used for unlabeled disks, and for floppies, to inhibit ! 76: * bad-sector forwarding. ! 77: */ ! 78: #define RAWDISK 8 /* raw disk operation, no translation*/ ! 79: #define ISRAWSTATE(s) (RAWDISK&(s)) /* are we in a raw state? */ ! 80: #define DISKSTATE(s) (~RAWDISK&(s)) /* are we in a given state regardless ! 81: of raw or cooked mode? */ ! 82: ! 83: #define CLOSED 0 /* disk is closed. */ ! 84: /* "cooked" disk states */ ! 85: #define WANTOPEN 1 /* open requested, not started */ ! 86: #define RECAL 2 /* doing restore */ ! 87: #define RDLABEL 3 /* reading pack label */ ! 88: #define RDBADTBL 4 /* reading bad-sector table */ ! 89: #define OPEN 5 /* done with open */ ! 90: ! 91: #define WANTOPENRAW (WANTOPEN|RAWDISK) /* raw WANTOPEN */ ! 92: #define RECALRAW (RECAL|RAWDISK) /* raw open, doing restore */ ! 93: #define OPENRAW (OPEN|RAWDISK) /* open, but unlabeled disk or floppy */ ! 94: ! 95: ! 96: /* ! 97: * The structure of a disk drive. ! 98: */ ! 99: struct disk { ! 100: struct disklabel dk_dd; /* device configuration data */ ! 101: long dk_bc; /* byte count left */ ! 102: short dk_skip; /* blocks already transferred */ ! 103: char dk_unit; /* physical unit number */ ! 104: char dk_state; /* control state */ ! 105: u_char dk_status; /* copy of status reg. */ ! 106: u_char dk_error; /* copy of error reg. */ ! 107: short dk_open; /* open/closed refcnt */ ! 108: u_long dk_copenpart; /* character units open on this drive */ ! 109: u_long dk_bopenpart; /* block units open on this drive */ ! 110: u_long dk_openpart; /* all units open on this drive */ ! 111: short dk_wlabel; /* label writable? */ ! 112: }; ! 113: ! 114: /* ! 115: * This label is used as a default when initializing a new or raw disk. ! 116: * It really only lets us access the first track until we know more. ! 117: */ ! 118: struct disklabel dflt_sizes = { ! 119: DISKMAGIC, DTYPE_ST506, 0, "default", "", ! 120: 512, /* sector size */ ! 121: 17, /* # of sectors per track */ ! 122: 8, /* # of tracks per cylinder */ ! 123: 766, /* # of cylinders per unit */ ! 124: 17*8, /* # of sectors per cylinder */ ! 125: 766*8*17, /* # of sectors per unit */ ! 126: 0, /* # of spare sectors per track */ ! 127: 0, /* # of spare sectors per cylinder */ ! 128: 0, /* # of alt. cylinders per unit */ ! 129: 3600, /* rotational speed */ ! 130: 1, /* hardware sector interleave */ ! 131: 0, /* sector 0 skew, per track */ ! 132: 0, /* sector 0 skew, per cylinder */ ! 133: 0, /* head switch time, usec */ ! 134: 0, /* track-to-track seek, usec */ ! 135: 0, /* generic flags */ ! 136: 0,0,0,0,0, ! 137: 0,0,0,0,0, ! 138: DISKMAGIC, ! 139: 0, ! 140: 8, ! 141: 8192, ! 142: 8192, ! 143: ! 144: {{21600, 0, 0,0,0,0}, /* A=root filesystem */ ! 145: {21600, 40, 0,0,0,0}, ! 146: {660890, 0, 0,0,0,0}, /* C=whole disk */ ! 147: {216000, 80, 0,0,0,0}, ! 148: {0, 0, 0,0,0,0}, ! 149: {0, 0, 0,0,0,0}, ! 150: {0, 0, 0,0,0,0}, ! 151: {399600, 480, 0,0,0,0}} ! 152: }; ! 153: ! 154: static struct dkbad dkbad[NWD]; ! 155: struct disk wddrives[NWD] = {0}; /* table of units */ ! 156: struct buf wdtab = {0}; ! 157: struct buf wdutab[NWD] = {0}; /* head of queue per drive */ ! 158: struct buf rwdbuf[NWD] = {0}; /* buffers for raw IO */ ! 159: long wdxfer[NWD] = {0}; /* count of transfers */ ! 160: int writeprotected[NWD] = { 0 }; ! 161: int wdprobe(), wdattach(), wdintr(); ! 162: struct isa_driver wddriver = { ! 163: wdprobe, wdattach, "wd", ! 164: }; ! 165: ! 166: static wdc; ! 167: /* ! 168: * Probe routine ! 169: */ ! 170: wdprobe(dvp) ! 171: struct isa_device *dvp; ! 172: { ! 173: wdc = dvp->id_iobase; ! 174: ! 175: #ifdef lint ! 176: wdintr(0); ! 177: #endif ! 178: /* XXX sorry, needs to be better */ ! 179: outb(wdc+wd_error, 0x5a) ; /* error register not writable */ ! 180: outb(wdc+wd_cyl_lo, 0xa5) ; /* but all of cyllo are implemented */ ! 181: if(inb(wdc+wd_error) != 0x5a && inb(wdc+wd_cyl_lo) == 0xa5) ! 182: return(1) ; ! 183: return (0); ! 184: } ! 185: ! 186: /* ! 187: * attach each drive if possible. ! 188: */ ! 189: wdattach(dvp) ! 190: struct isa_device *dvp; ! 191: { ! 192: int unit = dvp->id_unit; ! 193: ! 194: outb(wdc+wd_ctlr,12); ! 195: DELAY(1000); ! 196: outb(wdc+wd_ctlr,8); ! 197: } ! 198: ! 199: /* Read/write routine for a buffer. Finds the proper unit, range checks ! 200: * arguments, and schedules the transfer. Does not wait for the transfer ! 201: * to complete. Multi-page transfers are supported. All I/O requests must ! 202: * be a multiple of a sector in length. ! 203: */ ! 204: wdstrategy(bp) ! 205: register struct buf *bp; /* IO operation to perform */ ! 206: { ! 207: register struct buf *dp; ! 208: register struct disk *du; /* Disk unit to do the IO. */ ! 209: register struct partition *p; ! 210: long maxsz, sz; ! 211: int unit = wdunit(bp->b_dev); ! 212: int s; ! 213: ! 214: if ((unit >= NWD) || (bp->b_blkno < 0)) { ! 215: printf("wdstrat: unit = %d, blkno = %d, bcount = %d\n", ! 216: unit, bp->b_blkno, bp->b_bcount); ! 217: pg("wd:error in wdstrategy"); ! 218: bp->b_flags |= B_ERROR; ! 219: goto bad; ! 220: } ! 221: if (writeprotected[unit] && (bp->b_flags & B_READ) == 0) { ! 222: printf("wd%d: write protected\n", unit); ! 223: goto bad; ! 224: } ! 225: du = &wddrives[unit]; ! 226: if (DISKSTATE(du->dk_state) != OPEN) ! 227: goto q; ! 228: #ifdef old ! 229: /* ! 230: * Convert DEV_BSIZE "blocks" to sectors. ! 231: * Note: doing the conversions this way limits the partition size ! 232: * to about 8 million sectors (1-8 Gb). ! 233: */ ! 234: blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize; ! 235: if (((u_long) bp->b_blkno * DEV_BSIZE % du->dk_dd.d_secsize != 0) || ! 236: bp->b_bcount >= MAXTRANSFER * CLBYTES) { ! 237: bp->b_flags |= B_ERROR; ! 238: goto bad; ! 239: } ! 240: nblocks = du->dk_dd.d_partitions[part].p_size; ! 241: cyloff = du->dk_dd.d_partitions[part].p_offset; ! 242: if (blknum + (bp->b_bcount / du->dk_dd.d_secsize) > nblocks) { ! 243: if (blknum == nblocks) ! 244: bp->b_resid = bp->b_bcount; ! 245: else ! 246: bp->b_flags |= B_ERROR; ! 247: goto bad; ! 248: } ! 249: bp->b_cylin = blknum / du->dk_dd.d_secpercyl + cyloff; ! 250: #else ! 251: /* ! 252: * Determine the size of the transfer, and make sure it is ! 253: * within the boundaries of the partition. ! 254: */ ! 255: p = &du->dk_dd.d_partitions[wdpart(bp->b_dev)]; ! 256: maxsz = p->p_size; ! 257: sz = (bp->b_bcount + DEV_BSIZE - 1) >> DEV_BSHIFT; ! 258: if (bp->b_blkno + p->p_offset <= LABELSECTOR && ! 259: #if LABELSECTOR != 0 ! 260: bp->b_blkno + p->p_offset + sz > LABELSECTOR && ! 261: #endif ! 262: (bp->b_flags & B_READ) == 0 && du->dk_wlabel == 0) { ! 263: bp->b_error = EROFS; ! 264: goto bad; ! 265: } ! 266: if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { ! 267: /* if exactly at end of disk, return an EOF */ ! 268: if (bp->b_blkno == maxsz) { ! 269: bp->b_resid = bp->b_bcount; ! 270: biodone(bp); ! 271: return; ! 272: } ! 273: /* or truncate if part of it fits */ ! 274: sz = maxsz - bp->b_blkno; ! 275: if (sz <= 0) ! 276: goto bad; ! 277: bp->b_bcount = sz << DEV_BSHIFT; ! 278: } ! 279: bp->b_cylin = (bp->b_blkno + p->p_offset) / du->dk_dd.d_secpercyl; ! 280: #endif ! 281: q: ! 282: dp = &wdutab[unit]; ! 283: s = splhigh(); ! 284: disksort(dp, bp); ! 285: if (dp->b_active == 0) ! 286: wdustart(du); /* start drive if idle */ ! 287: if (wdtab.b_active == 0) ! 288: wdstart(s); /* start IO if controller idle */ ! 289: splx(s); ! 290: return; ! 291: ! 292: bad: ! 293: bp->b_error = EINVAL; ! 294: biodone(bp); ! 295: } ! 296: ! 297: /* Routine to queue a read or write command to the controller. The request is ! 298: * linked into the active list for the controller. If the controller is idle, ! 299: * the transfer is started. ! 300: */ ! 301: wdustart(du) ! 302: register struct disk *du; ! 303: { ! 304: register struct buf *bp, *dp; ! 305: ! 306: dp = &wdutab[du->dk_unit]; ! 307: if (dp->b_active) ! 308: return; ! 309: bp = dp->b_actf; ! 310: if (bp == NULL) ! 311: return; ! 312: dp->b_forw = NULL; ! 313: if (wdtab.b_actf == NULL) /* link unit into active list */ ! 314: wdtab.b_actf = dp; ! 315: else ! 316: wdtab.b_actl->b_forw = dp; ! 317: wdtab.b_actl = dp; ! 318: dp->b_active = 1; /* mark the drive as busy */ ! 319: } ! 320: ! 321: /* ! 322: * Controller startup routine. This does the calculation, and starts ! 323: * a single-sector read or write operation. Called to start a transfer, ! 324: * or from the interrupt routine to continue a multi-sector transfer. ! 325: * RESTRICTIONS: ! 326: * 1. The transfer length must be an exact multiple of the sector size. ! 327: */ ! 328: ! 329: static wd_sebyse; ! 330: ! 331: wdstart() ! 332: { ! 333: register struct disk *du; /* disk unit for IO */ ! 334: register struct buf *bp; ! 335: struct buf *dp; ! 336: register struct bt_bad *bt_ptr; ! 337: long blknum, pagcnt, cylin, head, sector; ! 338: long secpertrk, secpercyl, addr, i; ! 339: int unit, s; ! 340: ! 341: loop: ! 342: dp = wdtab.b_actf; ! 343: if (dp == NULL) ! 344: return; ! 345: bp = dp->b_actf; ! 346: if (bp == NULL) { ! 347: wdtab.b_actf = dp->b_forw; ! 348: goto loop; ! 349: } ! 350: unit = wdunit(bp->b_dev); ! 351: du = &wddrives[unit]; ! 352: if (DISKSTATE(du->dk_state) <= RDLABEL) { ! 353: if (wdcontrol(bp)) { ! 354: dp->b_actf = bp->av_forw; ! 355: goto loop; /* done */ ! 356: } ! 357: return; ! 358: } ! 359: secpertrk = du->dk_dd.d_nsectors; ! 360: secpercyl = du->dk_dd.d_secpercyl; ! 361: /* ! 362: * Convert DEV_BSIZE "blocks" to sectors. ! 363: */ ! 364: blknum = (unsigned long) bp->b_blkno * DEV_BSIZE / du->dk_dd.d_secsize ! 365: + du->dk_skip; ! 366: #ifdef WDDEBUG ! 367: if (du->dk_skip == 0) { ! 368: dprintf(DDSK,"\nwdstart %d: %s %d@%d; map ", unit, ! 369: (bp->b_flags & B_READ) ? "read" : "write", ! 370: bp->b_bcount, blknum); ! 371: } else { ! 372: dprintf(DDSK," %d)%x", du->dk_skip, inb(wdc+wd_altsts)); ! 373: } ! 374: #endif ! 375: ! 376: addr = (int) bp->b_un.b_addr; ! 377: if(du->dk_skip==0) du->dk_bc = bp->b_bcount; ! 378: cylin = blknum / secpercyl; ! 379: head = (blknum % secpercyl) / secpertrk; ! 380: sector = blknum % secpertrk; ! 381: if (DISKSTATE(du->dk_state) == OPEN) ! 382: cylin += du->dk_dd.d_partitions[wdpart(bp->b_dev)].p_offset ! 383: / secpercyl; ! 384: ! 385: /* ! 386: * See if the current block is in the bad block list. ! 387: * (If we have one, and not formatting.) ! 388: */ ! 389: if (DISKSTATE(du->dk_state) == OPEN && wd_sebyse) ! 390: for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) { ! 391: if (bt_ptr->bt_cyl > cylin) ! 392: /* Sorted list, and we passed our cylinder. quit. */ ! 393: break; ! 394: if (bt_ptr->bt_cyl == cylin && ! 395: bt_ptr->bt_trksec == (head << 8) + sector) { ! 396: /* ! 397: * Found bad block. Calculate new block addr. ! 398: * This starts at the end of the disk (skip the ! 399: * last track which is used for the bad block list), ! 400: * and works backwards to the front of the disk. ! 401: */ ! 402: #ifdef WDDEBUG ! 403: dprintf(DDSK,"--- badblock code -> Old = %d; ", ! 404: blknum); ! 405: #endif ! 406: blknum = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors ! 407: - (bt_ptr - dkbad[unit].bt_bad) - 1; ! 408: cylin = blknum / secpercyl; ! 409: head = (blknum % secpercyl) / secpertrk; ! 410: sector = blknum % secpertrk; ! 411: #ifdef WDDEBUG ! 412: dprintf(DDSK, "new = %d\n", blknum); ! 413: #endif ! 414: break; ! 415: } ! 416: } ! 417: sector += 1; /* sectors begin with 1, not 0 */ ! 418: ! 419: wdtab.b_active = 1; /* mark controller active */ ! 420: ! 421: if(du->dk_skip==0 || wd_sebyse) { ! 422: if(wdtab.b_errcnt && (bp->b_flags & B_READ) == 0) du->dk_bc += 512; ! 423: while ((inb(wdc+wd_status) & WDCS_BUSY) != 0) ; ! 424: /*while ((inb(wdc+wd_status) & WDCS_DRQ)) inb(wdc+wd_data);*/ ! 425: outb(wdc+wd_precomp, 0xff); ! 426: /*wr(wdc+wd_precomp, du->dk_dd.dk_precompcyl / 4);*/ ! 427: /*if (bp->b_flags & B_FORMAT) { ! 428: wr(wdc+wd_sector, du->dk_dd.dk_gap3); ! 429: wr(wdc+wd_seccnt, du->dk_dd.dk_nsectors); ! 430: } else {*/ ! 431: if(wd_sebyse) ! 432: outb(wdc+wd_seccnt, 1); ! 433: else ! 434: outb(wdc+wd_seccnt, ((du->dk_bc +511) / 512)); ! 435: outb(wdc+wd_sector, sector); ! 436: ! 437: outb(wdc+wd_cyl_lo, cylin); ! 438: outb(wdc+wd_cyl_hi, cylin >> 8); ! 439: ! 440: /* Set up the SDH register (select drive). */ ! 441: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); ! 442: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ; ! 443: ! 444: /*if (bp->b_flags & B_FORMAT) ! 445: wr(wdc+wd_command, WDCC_FORMAT); ! 446: else*/ ! 447: outb(wdc+wd_command, ! 448: (bp->b_flags & B_READ)? WDCC_READ : WDCC_WRITE); ! 449: #ifdef WDDEBUG ! 450: dprintf(DDSK,"sector %d cylin %d head %d addr %x sts %x\n", ! 451: sector, cylin, head, addr, inb(wdc+wd_altsts)); ! 452: #endif ! 453: } ! 454: ! 455: /* If this is a read operation, just go away until it's done. */ ! 456: if (bp->b_flags & B_READ) return; ! 457: ! 458: /* Ready to send data? */ ! 459: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0); ! 460: ! 461: /* ASSUMES CONTIGUOUS MEMORY */ ! 462: outsw (wdc+wd_data, addr+du->dk_skip*512, 256); ! 463: du->dk_bc -= 512; ! 464: } ! 465: ! 466: /* ! 467: * these are globally defined so they can be found ! 468: * by the debugger easily in the case of a system crash ! 469: */ ! 470: daddr_t wd_errsector; ! 471: daddr_t wd_errbn; ! 472: unsigned char wd_errstat; ! 473: ! 474: /* Interrupt routine for the controller. Acknowledge the interrupt, check for ! 475: * errors on the current operation, mark it done if necessary, and start ! 476: * the next request. Also check for a partially done transfer, and ! 477: * continue with the next chunk if so. ! 478: */ ! 479: wdintr(unit) ! 480: { ! 481: register struct disk *du; ! 482: register struct buf *bp, *dp; ! 483: int status; ! 484: char partch ; ! 485: static wd_haderror; ! 486: ! 487: /* Shouldn't need this, but it may be a slow controller. */ ! 488: while ((status = inb(wdc+wd_status)) & WDCS_BUSY) ; ! 489: if (!wdtab.b_active) { ! 490: printf("wd: extra interrupt\n"); ! 491: return; ! 492: } ! 493: ! 494: #ifdef WDDEBUG ! 495: dprintf(DDSK,"I "); ! 496: #endif ! 497: dp = wdtab.b_actf; ! 498: bp = dp->b_actf; ! 499: du = &wddrives[wdunit(bp->b_dev)]; ! 500: partch = wdpart(bp->b_dev) + 'a'; ! 501: if (DISKSTATE(du->dk_state) <= RDLABEL) { ! 502: if (wdcontrol(bp)) ! 503: goto done; ! 504: return; ! 505: } ! 506: if (status & (WDCS_ERR | WDCS_ECCCOR)) { ! 507: wd_errstat = inb(wdc+wd_error); /* save error status */ ! 508: #ifdef WDDEBUG ! 509: printf("status %x error %x\n", status, wd_errstat); ! 510: #endif ! 511: if(wd_sebyse == 0) { ! 512: wd_haderror = 1; ! 513: goto outt; ! 514: } ! 515: /*if (bp->b_flags & B_FORMAT) { ! 516: du->dk_status = status; ! 517: du->dk_error = wdp->wd_error; ! 518: bp->b_flags |= B_ERROR; ! 519: goto done; ! 520: }*/ ! 521: ! 522: wd_errsector = (bp->b_cylin * du->dk_dd.d_secpercyl) + ! 523: (((unsigned long) bp->b_blkno * DEV_BSIZE / ! 524: du->dk_dd.d_secsize) % du->dk_dd.d_secpercyl) + ! 525: du->dk_skip; ! 526: wd_errbn = bp->b_blkno ! 527: + du->dk_skip * du->dk_dd.d_secsize / DEV_BSIZE ; ! 528: if (status & WDCS_ERR) { ! 529: if (++wdtab.b_errcnt < RETRIES) { ! 530: wdtab.b_active = 0; ! 531: } else { ! 532: printf("wd%d%c: ", du->dk_unit, partch); ! 533: printf( ! 534: "hard %s error, sn %d bn %d status %b error %b\n", ! 535: (bp->b_flags & B_READ)? "read":"write", ! 536: wd_errsector, wd_errbn, status, WDCS_BITS, ! 537: wd_errstat, WDERR_BITS); ! 538: bp->b_flags |= B_ERROR; /* flag the error */ ! 539: } ! 540: } else ! 541: log(LOG_WARNING,"wd%d%c: soft ecc sn %d bn %d\n", ! 542: du->dk_unit, partch, wd_errsector, ! 543: wd_errbn); ! 544: } ! 545: outt: ! 546: ! 547: /* ! 548: * If this was a successful read operation, fetch the data. ! 549: */ ! 550: if (((bp->b_flags & (B_READ | B_ERROR)) == B_READ) && wdtab.b_active) { ! 551: int chk, dummy; ! 552: ! 553: chk = min(256,du->dk_bc/2); ! 554: /* Ready to receive data? */ ! 555: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ; ! 556: ! 557: /*dprintf(DDSK,"addr %x\n", (int)bp->b_un.b_addr + du->dk_skip * 512);*/ ! 558: insw(wdc+wd_data,(int)bp->b_un.b_addr + du->dk_skip * 512 ,chk); ! 559: du->dk_bc -= 2*chk; ! 560: while (chk++ < 256) insw (wdc+wd_data,&dummy,1); ! 561: } ! 562: ! 563: wdxfer[du->dk_unit]++; ! 564: if (wdtab.b_active) { ! 565: if ((bp->b_flags & B_ERROR) == 0) { ! 566: du->dk_skip++; /* Add to successful sectors. */ ! 567: if (wdtab.b_errcnt) { ! 568: log(LOG_WARNING, "wd%d%c: ", ! 569: du->dk_unit, partch); ! 570: log(LOG_WARNING, ! 571: "soft %s error, sn %d bn %d error %b retries %d\n", ! 572: (bp->b_flags & B_READ) ? "read" : "write", ! 573: wd_errsector, wd_errbn, wd_errstat, ! 574: WDERR_BITS, wdtab.b_errcnt); ! 575: } ! 576: wdtab.b_errcnt = 0; ! 577: ! 578: /* see if more to transfer */ ! 579: /*if (du->dk_skip < (bp->b_bcount + 511) / 512) {*/ ! 580: if (du->dk_bc > 0 && wd_haderror == 0) { ! 581: wdstart(); ! 582: return; /* next chunk is started */ ! 583: } else if (wd_haderror && wd_sebyse == 0) { ! 584: du->dk_skip = 0; ! 585: wd_haderror = 0; ! 586: wd_sebyse = 1; ! 587: wdstart(); ! 588: return; /* redo xfer sector by sector */ ! 589: } ! 590: } ! 591: ! 592: done: ! 593: wd_sebyse = 0; ! 594: /* done with this transfer, with or without error */ ! 595: wdtab.b_actf = dp->b_forw; ! 596: wdtab.b_errcnt = 0; ! 597: du->dk_skip = 0; ! 598: dp->b_active = 0; ! 599: dp->b_actf = bp->av_forw; ! 600: dp->b_errcnt = 0; ! 601: bp->b_resid = 0; ! 602: biodone(bp); ! 603: } ! 604: wdtab.b_active = 0; ! 605: if (dp->b_actf) ! 606: wdustart(du); /* requeue disk if more io to do */ ! 607: if (wdtab.b_actf) ! 608: wdstart(); /* start IO on next drive */ ! 609: } ! 610: ! 611: /* ! 612: * Initialize a drive. ! 613: */ ! 614: wdopen(dev, flags, fmt) ! 615: dev_t dev; ! 616: int flags, fmt; ! 617: { ! 618: register unsigned int unit; ! 619: register struct buf *bp; ! 620: register struct disk *du; ! 621: int part = wdpart(dev), mask = 1 << part; ! 622: struct partition *pp; ! 623: struct dkbad *db; ! 624: int i, error = 0; ! 625: ! 626: unit = wdunit(dev); ! 627: if (unit >= NWD) return (ENXIO) ; ! 628: du = &wddrives[unit]; ! 629: #ifdef notdef ! 630: if (du->dk_open){ ! 631: du->dk_open++ ; ! 632: return(0); /* already is open, don't mess with it */ ! 633: } ! 634: #endif ! 635: du->dk_unit = unit; ! 636: wdutab[unit].b_actf = NULL; ! 637: /*if (flags & O_NDELAY) ! 638: du->dk_state = WANTOPENRAW; ! 639: else*/ ! 640: du->dk_state = WANTOPEN; ! 641: /* ! 642: * Use the default sizes until we've read the label, ! 643: * or longer if there isn't one there. ! 644: */ ! 645: du->dk_dd = dflt_sizes; ! 646: ! 647: /* ! 648: * Recal, read of disk label will be done in wdcontrol ! 649: * during first read operation. ! 650: */ ! 651: bp = geteblk(512); ! 652: bp->b_dev = dev & 0xff00; ! 653: bp->b_bcount = 0; ! 654: bp->b_blkno = LABELSECTOR; ! 655: bp->b_flags = B_READ; ! 656: wdstrategy(bp); ! 657: biowait(bp); ! 658: if (bp->b_flags & B_ERROR) { ! 659: error = ENXIO; ! 660: du->dk_state = CLOSED; ! 661: goto done; ! 662: } ! 663: if (du->dk_state == OPENRAW) { ! 664: du->dk_state = OPENRAW; ! 665: goto done; ! 666: } ! 667: /* ! 668: * Read bad sector table into memory. ! 669: */ ! 670: i = 0; ! 671: do { ! 672: bp->b_flags = B_BUSY | B_READ; ! 673: bp->b_blkno = du->dk_dd.d_secperunit - du->dk_dd.d_nsectors ! 674: + i; ! 675: if (du->dk_dd.d_secsize > DEV_BSIZE) ! 676: bp->b_blkno *= du->dk_dd.d_secsize / DEV_BSIZE; ! 677: else ! 678: bp->b_blkno /= DEV_BSIZE / du->dk_dd.d_secsize; ! 679: bp->b_bcount = du->dk_dd.d_secsize; ! 680: bp->b_cylin = du->dk_dd.d_ncylinders - 1; ! 681: wdstrategy(bp); ! 682: biowait(bp); ! 683: } while ((bp->b_flags & B_ERROR) && (i += 2) < 10 && ! 684: i < du->dk_dd.d_nsectors); ! 685: db = (struct dkbad *)(bp->b_un.b_addr); ! 686: #define DKBAD_MAGIC 0x4321 ! 687: if ((bp->b_flags & B_ERROR) == 0 && db->bt_mbz == 0 && ! 688: db->bt_flag == DKBAD_MAGIC) { ! 689: dkbad[unit] = *db; ! 690: du->dk_state = OPEN; ! 691: } else { ! 692: printf("wd%d: %s bad-sector file\n", unit, ! 693: (bp->b_flags & B_ERROR) ? "can't read" : "format error in"); ! 694: error = ENXIO ; ! 695: du->dk_state = OPENRAW; ! 696: } ! 697: done: ! 698: bp->b_flags = B_INVAL | B_AGE; ! 699: brelse(bp); ! 700: if (error == 0) ! 701: du->dk_open = 1; ! 702: ! 703: /* ! 704: * Warn if a partion is opened ! 705: * that overlaps another partition which is open ! 706: * unless one is the "raw" partition (whole disk). ! 707: */ ! 708: #define RAWPART 8 /* 'x' partition */ /* XXX */ ! 709: if ((du->dk_openpart & mask) == 0 && part != RAWPART) { ! 710: int start, end; ! 711: ! 712: pp = &du->dk_dd.d_partitions[part]; ! 713: start = pp->p_offset; ! 714: end = pp->p_offset + pp->p_size; ! 715: for (pp = du->dk_dd.d_partitions; ! 716: pp < &du->dk_dd.d_partitions[du->dk_dd.d_npartitions]; ! 717: pp++) { ! 718: if (pp->p_offset + pp->p_size <= start || ! 719: pp->p_offset >= end) ! 720: continue; ! 721: if (pp - du->dk_dd.d_partitions == RAWPART) ! 722: continue; ! 723: if (du->dk_openpart & (1 << (pp - ! 724: du->dk_dd.d_partitions))) ! 725: log(LOG_WARNING, ! 726: "wd%d%c: overlaps open partition (%c)\n", ! 727: unit, part + 'a', ! 728: pp - du->dk_dd.d_partitions + 'a'); ! 729: } ! 730: } ! 731: if (part >= du->dk_dd.d_npartitions) ! 732: return (ENXIO); ! 733: du->dk_openpart |= mask; ! 734: switch (fmt) { ! 735: case S_IFCHR: ! 736: du->dk_copenpart |= mask; ! 737: break; ! 738: case S_IFBLK: ! 739: du->dk_bopenpart |= mask; ! 740: break; ! 741: } ! 742: return (error); ! 743: } ! 744: ! 745: /* ! 746: * Implement operations other than read/write. ! 747: * Called from wdstart or wdintr during opens and formats. ! 748: * Uses finite-state-machine to track progress of operation in progress. ! 749: * Returns 0 if operation still in progress, 1 if completed. ! 750: */ ! 751: wdcontrol(bp) ! 752: register struct buf *bp; ! 753: { ! 754: register struct disk *du; ! 755: register unit; ! 756: unsigned char stat; ! 757: int s, cnt; ! 758: extern int bootdev, cyloffset; ! 759: ! 760: du = &wddrives[wdunit(bp->b_dev)]; ! 761: unit = du->dk_unit; ! 762: switch (DISKSTATE(du->dk_state)) { ! 763: ! 764: tryagainrecal: ! 765: case WANTOPEN: /* set SDH, step rate, do restore */ ! 766: #ifdef WDDEBUG ! 767: dprintf(DDSK,"wd%d: recal ", unit); ! 768: #endif ! 769: s = splbio(); /* not called from intr level ... */ ! 770: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); ! 771: wdtab.b_active = 1; ! 772: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); ! 773: du->dk_state++; ! 774: splx(s); ! 775: return(0); ! 776: ! 777: case RECAL: ! 778: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) { ! 779: printf("wd%d: recal", du->dk_unit); ! 780: if (unit == 0) { ! 781: printf(": status %b error %b\n", ! 782: stat, WDCS_BITS, ! 783: inb(wdc+wd_error), WDERR_BITS); ! 784: if (++wdtab.b_errcnt < RETRIES) ! 785: goto tryagainrecal; ! 786: } ! 787: goto badopen; ! 788: } ! 789: ! 790: /* some compaq controllers require this ... */ ! 791: wdsetctlr(bp->b_dev, du); ! 792: ! 793: wdtab.b_errcnt = 0; ! 794: if (ISRAWSTATE(du->dk_state)) { ! 795: du->dk_state = OPENRAW; ! 796: return(1); ! 797: } ! 798: retry: ! 799: #ifdef WDDEBUG ! 800: dprintf(DDSK,"rdlabel "); ! 801: #endif ! 802: if( cyloffset < 0 || cyloffset > 8192) cyloffset=0; ! 803: /* ! 804: * Read in sector LABELSECTOR to get the pack label ! 805: * and geometry. ! 806: */ ! 807: outb(wdc+wd_precomp, 0xff);/* sometimes this is head bit 3 */ ! 808: outb(wdc+wd_seccnt, 1); ! 809: outb(wdc+wd_sector, LABELSECTOR+1); ! 810: /*if (bp->b_dev == bootdev) { ! 811: (wdc+wd_cyl_lo = cyloffset & 0xff; ! 812: (wdc+wd_cyl_hi = cyloffset >> 8; ! 813: } else { ! 814: (wdc+wd_cyl_lo = 0; ! 815: (wdc+wd_cyl_hi = 0; ! 816: }*/ ! 817: outb(wdc+wd_cyl_lo, (cyloffset & 0xff)); ! 818: outb(wdc+wd_cyl_hi, (cyloffset >> 8)); ! 819: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); ! 820: outb(wdc+wd_command, WDCC_READ); ! 821: du->dk_state = RDLABEL; ! 822: return(0); ! 823: ! 824: case RDLABEL: ! 825: if ((stat = inb(wdc+wd_status)) & WDCS_ERR) { ! 826: if (++wdtab.b_errcnt < RETRIES) ! 827: goto retry; ! 828: printf("wd%d: read label", unit); ! 829: goto badopen; ! 830: } ! 831: ! 832: insw(wdc+wd_data, bp->b_un.b_addr, 256); ! 833: ! 834: if (((struct disklabel *) ! 835: (bp->b_un.b_addr + LABELOFFSET))->d_magic == DISKMAGIC) { ! 836: du->dk_dd = ! 837: * (struct disklabel *) (bp->b_un.b_addr + LABELOFFSET); ! 838: } else { ! 839: printf("wd%d: bad disk label\n", du->dk_unit); ! 840: du->dk_state = OPENRAW; ! 841: } ! 842: ! 843: s = splbio(); /* not called from intr level ... */ ! 844: while ((stat = inb(wdc+wd_status)) & WDCS_BUSY); ! 845: ! 846: wdsetctlr(bp->b_dev, du); ! 847: ! 848: outb(wdc+wd_seccnt, 0); ! 849: splx(s); ! 850: ! 851: if (du->dk_state == RDLABEL) ! 852: du->dk_state = RDBADTBL; ! 853: /* ! 854: * The rest of the initialization can be done ! 855: * by normal means. ! 856: */ ! 857: return(1); ! 858: ! 859: default: ! 860: panic("wdcontrol"); ! 861: } ! 862: /* NOTREACHED */ ! 863: ! 864: badopen: ! 865: printf(": status %b error %b\n", ! 866: stat, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); ! 867: du->dk_state = OPENRAW; ! 868: return(1); ! 869: } ! 870: ! 871: wdsetctlr(dev, du) dev_t dev; struct disk *du; { ! 872: int stat; ! 873: ! 874: outb(wdc+wd_cyl_lo, du->dk_dd.d_ncylinders); ! 875: outb(wdc+wd_cyl_hi, (du->dk_dd.d_ncylinders)>>8); ! 876: outb(wdc+wd_sdh, WDSD_IBM | (wdunit(dev) << 4) + du->dk_dd.d_ntracks-1); ! 877: outb(wdc+wd_seccnt, du->dk_dd.d_nsectors); ! 878: outb(wdc+wd_command, 0x91); ! 879: ! 880: while ((stat = inb(wdc+wd_status)) & WDCS_BUSY) ; ! 881: stat = inb(wdc+wd_error); ! 882: return(stat); ! 883: } ! 884: ! 885: /* ARGSUSED */ ! 886: wdclose(dev, flags, fmt) ! 887: dev_t dev; ! 888: int flags, fmt; ! 889: { ! 890: register struct disk *du; ! 891: ! 892: du = &wddrives[wdunit(dev)]; ! 893: du->dk_open-- ; ! 894: /*if (du->dk_open == 0) du->dk_state = CLOSED ; does not work */ ! 895: } ! 896: ! 897: wdioctl(dev,cmd,addr,flag) ! 898: dev_t dev; ! 899: caddr_t addr; ! 900: { ! 901: int unit = wdunit(dev); ! 902: register struct disk *du; ! 903: int error = 0; ! 904: struct uio auio; ! 905: struct iovec aiov; ! 906: /*int wdformat();*/ ! 907: ! 908: du = &wddrives[unit]; ! 909: ! 910: switch (cmd) { ! 911: ! 912: case DIOCGDINFO: ! 913: *(struct disklabel *)addr = du->dk_dd; ! 914: break; ! 915: ! 916: case DIOCGPART: ! 917: ((struct partinfo *)addr)->disklab = &du->dk_dd; ! 918: ((struct partinfo *)addr)->part = ! 919: &du->dk_dd.d_partitions[wdpart(dev)]; ! 920: break; ! 921: ! 922: case DIOCSDINFO: ! 923: if ((flag & FWRITE) == 0) ! 924: error = EBADF; ! 925: else ! 926: error = setdisklabel(&du->dk_dd, ! 927: (struct disklabel *)addr, ! 928: 0 /*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/); ! 929: /*if (error == 0 && dk->dk_state == OPENRAW && ! 930: vdreset_drive(vddinfo[unit])) ! 931: dk->dk_state = OPEN;*/ ! 932: wdsetctlr(dev, du); ! 933: break; ! 934: ! 935: case DIOCWLABEL: ! 936: if ((flag & FWRITE) == 0) ! 937: error = EBADF; ! 938: else ! 939: du->dk_wlabel = *(int *)addr; ! 940: break; ! 941: ! 942: case DIOCWDINFO: ! 943: if ((flag & FWRITE) == 0) ! 944: error = EBADF; ! 945: else if ((error = setdisklabel(&du->dk_dd, (struct disklabel *)addr, ! 946: 0/*(dk->dk_state == OPENRAW) ? 0 : dk->dk_openpart*/)) == 0) { ! 947: int wlab; ! 948: ! 949: /*if (error == 0 && dk->dk_state == OPENRAW && ! 950: vdreset_drive(vddinfo[unit])) ! 951: dk->dk_state = OPEN; */ ! 952: wdsetctlr(dev, du); ! 953: ! 954: /* simulate opening partition 0 so write succeeds */ ! 955: /* dk->dk_openpart |= (1 << 0); /* XXX */ ! 956: wlab = du->dk_wlabel; ! 957: du->dk_wlabel = 1; ! 958: error = writedisklabel(dev, wdstrategy, &du->dk_dd,wdpart(dev)); ! 959: /*dk->dk_openpart = dk->dk_copenpart | dk->dk_bopenpart;*/ ! 960: du->dk_wlabel = wlab; ! 961: } ! 962: break; ! 963: ! 964: #ifdef notyet ! 965: case DIOCGDINFOP: ! 966: *(struct disklabel **)addr = &(du->dk_dd); ! 967: break; ! 968: ! 969: case DIOCWFORMAT: ! 970: if ((flag & FWRITE) == 0) ! 971: error = EBADF; ! 972: else { ! 973: register struct format_op *fop; ! 974: ! 975: fop = (struct format_op *)addr; ! 976: aiov.iov_base = fop->df_buf; ! 977: aiov.iov_len = fop->df_count; ! 978: auio.uio_iov = &aiov; ! 979: auio.uio_iovcnt = 1; ! 980: auio.uio_resid = fop->df_count; ! 981: auio.uio_segflg = 0; ! 982: auio.uio_offset = ! 983: fop->df_startblk * du->dk_dd.d_secsize; ! 984: error = physio(wdformat, &rwdbuf[unit], dev, B_WRITE, ! 985: minphys, &auio); ! 986: fop->df_count -= auio.uio_resid; ! 987: fop->df_reg[0] = du->dk_status; ! 988: fop->df_reg[1] = du->dk_error; ! 989: } ! 990: break; ! 991: #endif ! 992: ! 993: default: ! 994: error = ENOTTY; ! 995: break; ! 996: } ! 997: return (error); ! 998: } ! 999: ! 1000: /*wdformat(bp) ! 1001: struct buf *bp; ! 1002: { ! 1003: ! 1004: bp->b_flags |= B_FORMAT; ! 1005: return (wdstrategy(bp)); ! 1006: }*/ ! 1007: ! 1008: /* ! 1009: * Routines to do raw IO for a unit. ! 1010: */ ! 1011: wdread(dev, uio) /* character read routine */ ! 1012: dev_t dev; ! 1013: struct uio *uio; ! 1014: { ! 1015: int unit = wdunit(dev) ; ! 1016: ! 1017: if (unit >= NWD) return(ENXIO); ! 1018: return(physio(wdstrategy, &rwdbuf[unit], dev, B_READ, minphys, uio)); ! 1019: } ! 1020: ! 1021: ! 1022: wdwrite(dev, uio) /* character write routine */ ! 1023: dev_t dev; ! 1024: struct uio *uio; ! 1025: { ! 1026: int unit = wdunit(dev) ; ! 1027: ! 1028: if (unit >= NWD) return(ENXIO); ! 1029: return(physio(wdstrategy, &rwdbuf[unit], dev, B_WRITE, minphys, uio)); ! 1030: } ! 1031: ! 1032: wdsize(dev) ! 1033: dev_t dev; ! 1034: { ! 1035: register unit = wdunit(dev); ! 1036: register part = wdpart(dev); ! 1037: register struct disk *du; ! 1038: register val ; ! 1039: ! 1040: if (unit >= NWD) return(-1); ! 1041: if (wddrives[unit].dk_state == 0) { ! 1042: val = wdopen (dev, 0); ! 1043: if (val < 0) ! 1044: return (-1); ! 1045: } ! 1046: du = &wddrives[unit]; ! 1047: return((int)((u_long)du->dk_dd.d_partitions[part].p_size * ! 1048: du->dk_dd.d_secsize / 512)); ! 1049: } ! 1050: ! 1051: extern char *vmmap; /* poor name! */ ! 1052: ! 1053: wddump(dev) /* dump core after a system crash */ ! 1054: dev_t dev; ! 1055: { ! 1056: register struct disk *du; /* disk unit to do the IO */ ! 1057: register struct bt_bad *bt_ptr; ! 1058: long num; /* number of sectors to write */ ! 1059: int unit, part; ! 1060: long cyloff, blknum, blkcnt; ! 1061: long cylin, head, sector, stat; ! 1062: long secpertrk, secpercyl, nblocks, i; ! 1063: char *addr; ! 1064: extern int Maxmem; ! 1065: static wddoingadump = 0 ; ! 1066: extern CMAP1; ! 1067: extern char CADDR1[]; ! 1068: ! 1069: ! 1070: #ifdef ARGO ! 1071: outb(0x461,0); /* disable failsafe timer */ ! 1072: #endif ! 1073: addr = (char *) 0; /* starting address */ ! 1074: /* size of memory to dump */ ! 1075: num = Maxmem; ! 1076: unit = wdunit(dev); /* eventually support floppies? */ ! 1077: part = wdpart(dev); /* file system */ ! 1078: /* check for acceptable drive number */ ! 1079: if (unit >= NWD) return(ENXIO); ! 1080: ! 1081: du = &wddrives[unit]; ! 1082: /* was it ever initialized ? */ ! 1083: if (du->dk_state < OPEN) return (ENXIO) ; ! 1084: ! 1085: /* Convert to disk sectors */ ! 1086: num = (u_long) num * NBPG / du->dk_dd.d_secsize; ! 1087: ! 1088: /* check if controller active */ ! 1089: /*if (wdtab.b_active) return(EFAULT); */ ! 1090: if (wddoingadump) return(EFAULT); ! 1091: ! 1092: secpertrk = du->dk_dd.d_nsectors; ! 1093: secpercyl = du->dk_dd.d_secpercyl; ! 1094: nblocks = du->dk_dd.d_partitions[part].p_size; ! 1095: cyloff = du->dk_dd.d_partitions[part].p_offset / secpercyl; ! 1096: ! 1097: /*pg("xunit %x, nblocks %d, dumplo %d num %d\n", part,nblocks,dumplo,num);*/ ! 1098: /* check transfer bounds against partition size */ ! 1099: if ((dumplo < 0) || ((dumplo + num) > nblocks)) ! 1100: return(EINVAL); ! 1101: ! 1102: /*wdtab.b_active = 1; /* mark controller active for if we ! 1103: panic during the dump */ ! 1104: wddoingadump = 1 ; i = 100000 ; ! 1105: while ((inb(wdc+wd_status) & WDCS_BUSY) && (i-- > 0)) ; ! 1106: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); ! 1107: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); ! 1108: while (inb(wdc+wd_status) & WDCS_BUSY) ; ! 1109: ! 1110: /* some compaq controllers require this ... */ ! 1111: wdsetctlr(dev, du); ! 1112: ! 1113: blknum = dumplo; ! 1114: while (num > 0) { ! 1115: #ifdef notdef ! 1116: if (blkcnt > MAXTRANSFER) blkcnt = MAXTRANSFER; ! 1117: if ((blknum + blkcnt - 1) / secpercyl != blknum / secpercyl) ! 1118: blkcnt = secpercyl - (blknum % secpercyl); ! 1119: /* keep transfer within current cylinder */ ! 1120: #endif ! 1121: pmap_enter(pmap_kernel(), vmmap, addr, VM_PROT_READ, TRUE); ! 1122: ! 1123: /* compute disk address */ ! 1124: cylin = blknum / secpercyl; ! 1125: head = (blknum % secpercyl) / secpertrk; ! 1126: sector = blknum % secpertrk; ! 1127: cylin += cyloff; ! 1128: ! 1129: #ifdef notyet ! 1130: /* ! 1131: * See if the current block is in the bad block list. ! 1132: * (If we have one.) ! 1133: */ ! 1134: for (bt_ptr = dkbad[unit].bt_bad; ! 1135: bt_ptr->bt_cyl != -1; bt_ptr++) { ! 1136: if (bt_ptr->bt_cyl > cylin) ! 1137: /* Sorted list, and we passed our cylinder. ! 1138: quit. */ ! 1139: break; ! 1140: if (bt_ptr->bt_cyl == cylin && ! 1141: bt_ptr->bt_trksec == (head << 8) + sector) { ! 1142: /* ! 1143: * Found bad block. Calculate new block addr. ! 1144: * This starts at the end of the disk (skip the ! 1145: * last track which is used for the bad block list), ! 1146: * and works backwards to the front of the disk. ! 1147: */ ! 1148: blknum = (du->dk_dd.d_secperunit) ! 1149: - du->dk_dd.d_nsectors ! 1150: - (bt_ptr - dkbad[unit].bt_bad) - 1; ! 1151: cylin = blknum / secpercyl; ! 1152: head = (blknum % secpercyl) / secpertrk; ! 1153: sector = blknum % secpertrk; ! 1154: break; ! 1155: } ! 1156: ! 1157: #endif ! 1158: sector++; /* origin 1 */ ! 1159: ! 1160: /* select drive. */ ! 1161: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); ! 1162: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ; ! 1163: ! 1164: /* transfer some blocks */ ! 1165: outb(wdc+wd_sector, sector); ! 1166: outb(wdc+wd_seccnt,1); ! 1167: outb(wdc+wd_cyl_lo, cylin); ! 1168: outb(wdc+wd_cyl_hi, cylin >> 8); ! 1169: #ifdef notdef ! 1170: /* lets just talk about this first...*/ ! 1171: pg ("sdh 0%o sector %d cyl %d addr 0x%x", ! 1172: inb(wdc+wd_sdh), inb(wdc+wd_sector), ! 1173: inb(wdc+wd_cyl_hi)*256+inb(wdc+wd_cyl_lo), addr) ; ! 1174: #endif ! 1175: #ifdef ODYSSEUS ! 1176: if(cylin < 46 || cylin > 91)pg("oops"); ! 1177: #endif ! 1178: #ifdef PRIAM ! 1179: if(cylin < 40 || cylin > 79)pg("oops"); ! 1180: #endif ! 1181: outb(wdc+wd_command, WDCC_WRITE); ! 1182: ! 1183: /* Ready to send data? */ ! 1184: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ; ! 1185: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; ! 1186: ! 1187: outsw (wdc+wd_data, CADDR1+((int)addr&(NBPG-1)), 256); ! 1188: (int) addr += 512; ! 1189: ! 1190: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; ! 1191: /* Check data request (should be done). */ ! 1192: if (inb(wdc+wd_status) & WDCS_DRQ) return(EIO) ; ! 1193: ! 1194: /* wait for completion */ ! 1195: for ( i = 1000000 ; inb(wdc+wd_status) & WDCS_BUSY ; i--) { ! 1196: if (i < 0) return (EIO) ; ! 1197: } ! 1198: /* error check the xfer */ ! 1199: if (inb(wdc+wd_status) & WDCS_ERR) return(EIO) ; ! 1200: /* update block count */ ! 1201: num--; ! 1202: blknum++ ; ! 1203: if (num % 100 == 0) printf(".") ; ! 1204: } ! 1205: return(0); ! 1206: } ! 1207: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.