|
|
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.3 (Berkeley) 5/4/91 ! 37: */ ! 38: ! 39: /* device driver for winchester disk */ ! 40: ! 41: #include "param.h" ! 42: #include "dkbad.h" ! 43: #include "disklabel.h" ! 44: #include "i386/isa/isa.h" ! 45: #include "i386/isa/wdreg.h" ! 46: #include "saio.h" ! 47: ! 48: #define NWD 2 /* number of hard disk units supported, max 2 */ ! 49: #define RETRIES 5 /* number of retries before giving up */ ! 50: ! 51: int noretries, wdquiet; ! 52: /*#define WDDEBUG*/ ! 53: ! 54: #ifdef SMALL ! 55: extern struct disklabel disklabel; ! 56: #else ! 57: struct disklabel wdsizes[NWD]; ! 58: #endif ! 59: ! 60: extern cyloffset ; /* bootstrap's idea of cylinder for disklabel */ ! 61: ! 62: /* ! 63: * Record for the bad block forwarding code. ! 64: * This is initialized to be empty until the bad-sector table ! 65: * is read from the disk. ! 66: */ ! 67: #define TRKSEC(trk,sec) ((trk << 8) + sec) ! 68: ! 69: struct dkbad dkbad[NWD]; ! 70: static wdcport; ! 71: ! 72: wdopen(io) ! 73: register struct iob *io; ! 74: { ! 75: register struct disklabel *dd; ! 76: ! 77: #ifdef WDDEBUG ! 78: printf("wdopen "); ! 79: #endif ! 80: #ifdef SMALL ! 81: dd = &disklabel; ! 82: #else ! 83: dd = &wdsizes[io->i_unit]; ! 84: if (io->i_part > 8) ! 85: _stop("Invalid partition number"); ! 86: if(io->i_ctlr > 1) ! 87: _stop("Invalid controller number"); ! 88: #endif ! 89: if (wdinit(io)) ! 90: _stop("wd initialization error"); ! 91: io->i_boff = dd->d_partitions[io->i_part].p_offset ; ! 92: return(0); ! 93: } ! 94: ! 95: wdstrategy(io,func) ! 96: register struct iob *io; ! 97: { ! 98: register int iosize; /* number of sectors to do IO for this loop */ ! 99: register daddr_t sector; ! 100: int nblocks, cyloff; ! 101: int unit, partition; ! 102: char *address; ! 103: register struct disklabel *dd; ! 104: ! 105: unit = io->i_unit; ! 106: partition = io->i_part; ! 107: #ifdef WDDEBUG ! 108: printf("wdstrat %d %d ", unit, partition); ! 109: #endif ! 110: #ifdef SMALL ! 111: dd = &disklabel; ! 112: #else ! 113: dd = &wdsizes[unit]; ! 114: #endif ! 115: iosize = io->i_cc / dd->d_secsize; ! 116: /* ! 117: * Convert PGSIZE "blocks" to sectors. ! 118: * Note: doing the conversions this way limits the partition size ! 119: * to about 8 million sectors (1-8 Gb). ! 120: */ ! 121: sector = (unsigned long) io->i_bn * DEV_BSIZE / dd->d_secsize; ! 122: nblocks = dd->d_partitions[partition].p_size; ! 123: #ifndef SMALL ! 124: if (iosize < 0 || sector + iosize > nblocks || sector < 0) { ! 125: #ifdef WDDEBUG ! 126: printf("bn = %d; sectors = %d; partition = %d; fssize = %d\n", ! 127: io->i_bn, iosize, partition, nblocks); ! 128: #endif ! 129: printf("wdstrategy - I/O out of filesystem boundaries\n"); ! 130: return(-1); ! 131: } ! 132: if (io->i_bn * DEV_BSIZE % dd->d_secsize) { ! 133: printf("wdstrategy - transfer starts in midsector\n"); ! 134: return(-1); ! 135: } ! 136: if (io->i_cc % dd->d_secsize) { ! 137: printf("wd: transfer of partial sector\n"); ! 138: return(-1); ! 139: } ! 140: #endif ! 141: ! 142: address = io->i_ma; ! 143: while (iosize > 0) { ! 144: if (wdio(func, unit, sector, address)) ! 145: return(-1); ! 146: iosize--; ! 147: sector++; ! 148: address += dd->d_secsize; ! 149: } ! 150: return(io->i_cc); ! 151: } ! 152: ! 153: /* ! 154: * Routine to do a one-sector I/O operation, and wait for it ! 155: * to complete. ! 156: */ ! 157: wdio(func, unit, blknm, addr) ! 158: short *addr; ! 159: { ! 160: struct disklabel *dd; ! 161: register wdc = wdcport; ! 162: struct bt_bad *bt_ptr; ! 163: int i; ! 164: int retries = 0; ! 165: long cylin, head, sector; ! 166: u_char opcode, erro; ! 167: ! 168: #ifdef SMALL ! 169: dd = &disklabel; ! 170: #else ! 171: dd = &wdsizes[unit]; ! 172: #endif ! 173: if (func == F_WRITE) ! 174: opcode = WDCC_WRITE; ! 175: else ! 176: opcode = WDCC_READ; ! 177: ! 178: /* Calculate data for output. */ ! 179: cylin = blknm / dd->d_secpercyl; ! 180: head = (blknm % dd->d_secpercyl) / dd->d_nsectors; ! 181: sector = blknm % dd->d_nsectors; ! 182: ! 183: /* ! 184: * See if the current block is in the bad block list. ! 185: */ ! 186: if (blknm > BBSIZE/DEV_BSIZE) /* should be BBSIZE */ ! 187: for (bt_ptr = dkbad[unit].bt_bad; bt_ptr->bt_cyl != -1; bt_ptr++) { ! 188: if (bt_ptr->bt_cyl > cylin) ! 189: /* Sorted list, and we passed our cylinder. quit. */ ! 190: break; ! 191: if (bt_ptr->bt_cyl == cylin && ! 192: bt_ptr->bt_trksec == (head << 8) + sector) { ! 193: /* ! 194: * Found bad block. Calculate new block addr. ! 195: * This starts at the end of the disk (skip the ! 196: * last track which is used for the bad block list), ! 197: * and works backwards to the front of the disk. ! 198: */ ! 199: #ifdef WDDEBUG ! 200: printf("--- badblock code -> Old = %d; ", ! 201: blknm); ! 202: #endif ! 203: blknm = dd->d_secperunit - dd->d_nsectors ! 204: - (bt_ptr - dkbad[unit].bt_bad) - 1; ! 205: cylin = blknm / dd->d_secpercyl; ! 206: head = (blknm % dd->d_secpercyl) / dd->d_nsectors; ! 207: sector = blknm % dd->d_nsectors; ! 208: #ifdef WDDEBUG ! 209: printf("new = %d\n", blknm); ! 210: #endif ! 211: break; ! 212: } ! 213: } ! 214: ! 215: sector += 1; ! 216: retry: ! 217: #ifdef WDDEBUG ! 218: printf("sec %d sdh %x cylin %d ", sector, ! 219: WDSD_IBM | (unit<<4) | (head & 0xf), cylin); ! 220: #endif ! 221: outb(wdc+wd_precomp, 0xff); ! 222: outb(wdc+wd_seccnt, 1); ! 223: outb(wdc+wd_sector, sector); ! 224: outb(wdc+wd_cyl_lo, cylin); ! 225: outb(wdc+wd_cyl_hi, cylin >> 8); ! 226: ! 227: /* Set up the SDH register (select drive). */ ! 228: outb(wdc+wd_sdh, WDSD_IBM | (unit<<4) | (head & 0xf)); ! 229: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ; ! 230: ! 231: outb(wdc+wd_command, opcode); ! 232: while (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_BUSY)) ! 233: ; ! 234: /* Did we get an error? */ ! 235: if (opcode == WDCC_READ && (inb(wdc+wd_status) & WDCS_ERR)) ! 236: goto error; ! 237: ! 238: /* Ready to remove data? */ ! 239: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ; ! 240: ! 241: if (opcode == WDCC_READ) ! 242: insw(wdc+wd_data,addr,256); ! 243: else outsw(wdc+wd_data,addr,256); ! 244: ! 245: /* Check data request (should be done). */ ! 246: if (inb(wdc+wd_status) & WDCS_DRQ) goto error; ! 247: ! 248: while (opcode == WDCC_WRITE && (inb(wdc+wd_status) & WDCS_BUSY)) ; ! 249: ! 250: if (inb(wdc+wd_status) & WDCS_ERR) goto error; ! 251: ! 252: #ifdef WDDEBUG ! 253: printf("+"); ! 254: #endif ! 255: return (0); ! 256: error: ! 257: erro = inb(wdc+wd_error); ! 258: if (++retries < RETRIES) ! 259: goto retry; ! 260: if (!wdquiet) ! 261: #ifdef SMALL ! 262: printf("wd%d: hard error: sector %d status %x error %x\n", unit, ! 263: blknm, inb(wdc+wd_status), erro); ! 264: #else ! 265: printf("wd%d: hard %s error: sector %d status %b error %b\n", unit, ! 266: opcode == WDCC_READ? "read" : "write", blknm, ! 267: inb(wdc+wd_status), WDCS_BITS, erro, WDERR_BITS); ! 268: #endif ! 269: return (-1); ! 270: } ! 271: ! 272: wdinit(io) ! 273: struct iob *io; ! 274: { ! 275: register wdc; ! 276: struct disklabel *dd; ! 277: unsigned int unit; ! 278: struct dkbad *db; ! 279: int i, errcnt = 0; ! 280: char buf[512]; ! 281: static open[NWD]; ! 282: ! 283: unit = io->i_unit; ! 284: if (open[unit]) return(0); ! 285: ! 286: wdcport = io->i_ctlr ? IO_WD2 : IO_WD1; ! 287: wdc = wdcport; ! 288: ! 289: #ifdef SMALL ! 290: dd = &disklabel; ! 291: #else ! 292: /* reset controller */ ! 293: outb(wdc+wd_ctlr, 12); wait(10); outb(wdc+wd_ctlr, 8); ! 294: wdwait(); ! 295: ! 296: dd = &wdsizes[unit]; ! 297: ! 298: tryagainrecal: ! 299: /* set SDH, step rate, do restore to recalibrate drive */ ! 300: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); ! 301: wdwait(); ! 302: outb(wdc+wd_command, WDCC_RESTORE | WD_STEP); ! 303: wdwait(); ! 304: if ((i = inb(wdc+wd_status)) & WDCS_ERR) { ! 305: /*#ifdef SMALL ! 306: printf("wd%d: recal status %x error %x\n", ! 307: unit, i, inb(wdc+wd_error)); ! 308: #else*/ ! 309: printf("wd%d: recal status %b error %b\n", ! 310: unit, i, WDCS_BITS, inb(wdc+wd_error), WDERR_BITS); ! 311: /*#endif*/ ! 312: if (++errcnt < 10) ! 313: goto tryagainrecal; ! 314: return(-1); ! 315: } ! 316: ! 317: /* ! 318: * Some controllers require this (after a recal they ! 319: * revert to a logical translation mode to compensate for ! 320: * dos limitation on 10-bit cylinders -- *shudder* -wfj) ! 321: * note: cylinders *must* be fewer than or equal to 8 to ! 322: * compensate for some IDE drives that latch this for all time. ! 323: */ ! 324: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + 8 -1); ! 325: outb(wdc+wd_seccnt, 35 ); ! 326: outb(wdc+wd_cyl_lo, 1224); ! 327: outb(wdc+wd_cyl_hi, 1224/256); ! 328: outb(wdc+wd_command, 0x91); ! 329: while (inb(wdc+wd_status) & WDCS_BUSY) ; ! 330: ! 331: errcnt = 0; ! 332: retry: ! 333: /* ! 334: * Read in LABELSECTOR to get the pack label and geometry. ! 335: */ ! 336: outb(wdc+wd_precomp, 0xff); /* sometimes this is head bit 3 */ ! 337: outb(wdc+wd_seccnt, 1); ! 338: outb(wdc+wd_sector, LABELSECTOR + 1); ! 339: outb(wdc+wd_cyl_lo, (cyloffset & 0xff)); ! 340: outb(wdc+wd_cyl_hi, (cyloffset >> 8)); ! 341: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4)); ! 342: wdwait(); ! 343: outb(wdc+wd_command, WDCC_READ); ! 344: wdwait(); ! 345: if ((i = inb(wdc+wd_status)) & WDCS_ERR) { ! 346: int err; ! 347: ! 348: err = inb(wdc+wd_error); ! 349: if (++errcnt < RETRIES) ! 350: goto retry; ! 351: if (!wdquiet) ! 352: /*#ifdef SMALL ! 353: printf("wd%d: reading label, status %x error %x\n", ! 354: unit, i, err); ! 355: #else*/ ! 356: printf("wd%d: reading label, status %b error %b\n", ! 357: unit, i, WDCS_BITS, err, WDERR_BITS); ! 358: /*#endif*/ ! 359: return(-1); ! 360: } ! 361: ! 362: /* Ready to remove data? */ ! 363: while ((inb(wdc+wd_status) & WDCS_DRQ) == 0) ; ! 364: ! 365: i = insw(wdc+wd_data, buf, 256); ! 366: ! 367: #ifdef WDDEBUG ! 368: printf("magic %x,insw %x, %x\n", ! 369: ((struct disklabel *) (buf + LABELOFFSET))->d_magic, i, buf); ! 370: #endif ! 371: if (((struct disklabel *) (buf + LABELOFFSET))->d_magic == DISKMAGIC) { ! 372: *dd = * (struct disklabel *) (buf + LABELOFFSET); ! 373: open[unit] = 1; ! 374: } else { ! 375: if (!wdquiet) ! 376: printf("wd%d: bad disk label\n", unit); ! 377: if (io->i_flgs & F_FILE) return(-1); ! 378: dkbad[unit].bt_bad[0].bt_cyl = -1; ! 379: dd->d_secpercyl = 1999999 ; dd->d_nsectors = 17 ; ! 380: dd->d_secsize = 512; ! 381: outb(wdc+wd_precomp, 0xff); /* force head 3 bit off */ ! 382: return (0) ; ! 383: } ! 384: #endif SMALL ! 385: #ifdef SMALL ! 386: #ifdef WDDEBUG ! 387: printf("magic %x sect %d\n", dd->d_magic, dd->d_nsectors); ! 388: #endif ! 389: #endif SMALL ! 390: ! 391: ! 392: /* now that we know the disk geometry, tell the controller */ ! 393: outb(wdc+wd_cyl_lo, dd->d_ncylinders); ! 394: outb(wdc+wd_cyl_hi, (dd->d_ncylinders)>>8); ! 395: outb(wdc+wd_sdh, WDSD_IBM | (unit << 4) + dd->d_ntracks-1); ! 396: outb(wdc+wd_seccnt, dd->d_nsectors); ! 397: outb(wdc+wd_command, 0x91); ! 398: while (inb(wdc+wd_status) & WDCS_BUSY) ; ! 399: ! 400: dkbad[unit].bt_bad[0].bt_cyl = -1; ! 401: outb(wdc+wd_precomp, dd->d_precompcyl / 4); ! 402: ! 403: /* ! 404: * Read bad sector table into memory. ! 405: */ ! 406: i = 0; ! 407: do { ! 408: int blknm = dd->d_secperunit - dd->d_nsectors + i; ! 409: errcnt = wdio(F_READ, unit, blknm, buf); ! 410: } while (errcnt && (i += 2) < 10 && i < dd->d_nsectors); ! 411: db = (struct dkbad *)(buf); ! 412: #define DKBAD_MAGIC 0x4321 ! 413: if (errcnt == 0 && db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC) ! 414: dkbad[unit] = *db; ! 415: else { ! 416: if (!wdquiet) ! 417: printf("wd%d: error in bad-sector file\n", unit); ! 418: dkbad[unit].bt_bad[0].bt_cyl = -1; ! 419: } ! 420: return(0); ! 421: } ! 422: ! 423: wdwait() ! 424: { ! 425: register wdc = wdcport; ! 426: register i = 0; ! 427: ! 428: while (inb(wdc+wd_status) & WDCS_BUSY) ! 429: ; ! 430: while ((inb(wdc+wd_status) & WDCS_READY) == 0) ! 431: if (i++ > 100000) ! 432: return(-1); ! 433: return(0); ! 434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.