|
|
1.1 ! root 1: /* (-lgl ! 2: * COHERENT Driver Kit Version 1.1.0 ! 3: * Copyright (c) 1982, 1990 by Mark Williams Company. ! 4: * All rights reserved. May not be copied without permission. ! 5: * ! 6: * $Log: at.c,v $ ! 7: * Revision 1.11 91/11/12 07:48:34 bin ! 8: * 3204 kernel source for use with piggy's tboot code ! 9: * ! 10: * Revision 1.10 91/11/11 12:29:03 hal ! 11: * Use n_atdr. ! 12: * ! 13: * Revision 1.9 91/10/30 10:47:46 hal ! 14: * Get atparms from tboot. ! 15: * ! 16: * Revision 1.8 91/10/24 12:36:25 hal ! 17: * Bump ATSECS from 4 to 6. ! 18: * Poll HF_REG (3F6) rather than CSR_REG (1F6). ! 19: * COH 3.2.03. ! 20: * ! 21: * Revision 1.7 91/09/11 14:45:38 hal ! 22: * Trial patch for Seagate 157A problems. ! 23: * ! 24: * Revision 1.6 91/09/11 13:23:12 hal ! 25: * Explicit sys in include paths. AT_MAJOR. ! 26: * ! 27: * Revision 1.5 91/05/22 15:06:59 hal ! 28: * Don't force 8's bit of control byte. ! 29: * ! 30: * Revision 1.4 91/03/14 14:22:32 hal ! 31: * ! 32: -lgl) */ ! 33: /* ! 34: * This is a driver for the ! 35: * hard disk on the AT. ! 36: * ! 37: * Reads drive characteristics from ROM (thru interrupt vector 0x41 and 0x46). ! 38: * Reads partition information from disk. ! 39: */ ! 40: #include <sys/coherent.h> ! 41: #include <sys/fdisk.h> ! 42: #include <sys/hdioctl.h> ! 43: #include <sys/buf.h> ! 44: #include <sys/con.h> ! 45: #include <sys/devices.h> ! 46: #include <sys/stat.h> ! 47: #include <sys/uproc.h> ! 48: #include <sys/typed.h> ! 49: #include <errno.h> ! 50: ! 51: extern saddr_t sds; /* System Data Selector */ ! 52: extern short n_atdr; /* Number of "at" drives */ ! 53: ! 54: /* ! 55: * Configurable parameters ! 56: */ ! 57: #define HDIRQ 14 /* Level 14 */ ! 58: #define HDBASE 0x01F0 /* Port base */ ! 59: #define NDRIVE 2 /* only two drives supported */ ! 60: #define SOFTLIM 6 /* (7) num of retrys before diag */ ! 61: #define HARDLIM 8 /* number of retrys before fail */ ! 62: #define BADLIM 100 /* num to stop recov if flagged bad */ ! 63: ! 64: #define BIT(n) (1 << (n)) ! 65: ! 66: #define CMOSA 0x70 /* write cmos address to this port */ ! 67: #define CMOSD 0x71 /* read cmos data through this port */ ! 68: ! 69: #ifndef ATCACHE ! 70: # if VERBOSE > 0 ! 71: # define ATCACHE 2 /* local cache size in blocks */ ! 72: # else ! 73: # define ATCACHE 0 /* no cache for small code */ ! 74: # endif ! 75: #endif ! 76: ! 77: /* ! 78: * Driver configuration. ! 79: */ ! 80: void atload(); ! 81: void atunload(); ! 82: void atopen(); ! 83: void atread(); ! 84: void atwrite(); ! 85: int atioctl(); ! 86: void atwatch(); ! 87: void atblock(); ! 88: int nulldev(); ! 89: int nonedev(); ! 90: ! 91: CON atcon = { ! 92: DFBLK|DFCHR, /* Flags */ ! 93: AT_MAJOR, /* Major index */ ! 94: atopen, /* Open */ ! 95: nulldev, /* Close */ ! 96: atblock, /* Block */ ! 97: atread, /* Read */ ! 98: atwrite, /* Write */ ! 99: atioctl, /* Ioctl */ ! 100: nulldev, /* Powerfail */ ! 101: atwatch, /* Timeout */ ! 102: atload, /* Load */ ! 103: atunload /* Unload */ ! 104: }; ! 105: ! 106: /* ! 107: * Forward Referenced Functions. ! 108: */ ! 109: void atreset(); ! 110: int atdequeue(); ! 111: void atstart(); ! 112: void atintr(); ! 113: void atdefer(); ! 114: int aterror(); ! 115: void atrecov(); ! 116: void atdone(); ! 117: ! 118: /* ! 119: * I/O Port Addresses ! 120: */ ! 121: #define DATA_REG (HDBASE+0) /* data (r/w) */ ! 122: #define AUX_REG (HDBASE+1) /* error(r), write precomp cyl/4 (w) */ ! 123: #define NSEC_REG (HDBASE+2) /* sector count (r/w) */ ! 124: #define SEC_REG (HDBASE+3) /* sector number (r/w) */ ! 125: #define LCYL_REG (HDBASE+4) /* low cylinder (r/w) */ ! 126: #define HCYL_REG (HDBASE+5) /* high cylinder (r/w) */ ! 127: #define HDRV_REG (HDBASE+6) /* drive/head (r/w) (D<<4)+(1<<H) */ ! 128: #define CSR_REG (HDBASE+7) /* status (r), command (w) */ ! 129: #define HF_REG (HDBASE+0x206) /* secondary status(r)/control byte(w)*/ ! 130: ! 131: /* ! 132: * Error from AUX_REG (r) ! 133: */ ! 134: #define DAM_ERR BIT(0) /* data address mark not found */ ! 135: #define TR0_ERR BIT(1) /* track 000 not found */ ! 136: #define ABT_ERR BIT(2) /* aborted command */ ! 137: #define ID_ERR BIT(4) /* id not found */ ! 138: #define ECC_ERR BIT(6) /* data ecc error */ ! 139: #define BAD_ERR BIT(7) /* bad block detect */ ! 140: ! 141: /* ! 142: * Status from CSR_REG (r) ! 143: */ ! 144: #define ERR_ST BIT(0) /* error occurred */ ! 145: #define INDEX_ST BIT(1) /* index pulse */ ! 146: #define SOFT_ST BIT(2) /* soft (corrected) ECC error */ ! 147: #define DRQ_ST BIT(3) /* data request */ ! 148: #define SKC_ST BIT(4) /* seek complete */ ! 149: #define WFLT_ST BIT(5) /* improper drive operation */ ! 150: #define RDY_ST BIT(6) /* drive is ready */ ! 151: #define BSY_ST BIT(7) /* controller is busy */ ! 152: ! 153: ! 154: /* ! 155: * Commands to CSR_REG (w) ! 156: */ ! 157: #define RESTORE(rate) (0x10+(rate)) /* X */ ! 158: #define SEEK(rate) (0x70+(rate)) /* X */ ! 159: #define READ_CMD (0x20) /* X */ ! 160: #define WRITE_CMD (0x30) /* X */ ! 161: #define FORMAT_CMD (0x50) /* X */ ! 162: #define VERIFY_CMD (0x40) /* X */ ! 163: #define DIAGNOSE_CMD (0x90) /* X */ ! 164: #define SETPARM_CMD (0x91) /* X */ ! 165: ! 166: /* ! 167: * Device States. ! 168: */ ! 169: #define SIDLE 0 /* controller idle */ ! 170: #define SRETRY 1 /* seeking */ ! 171: #define SREAD 2 /* reading */ ! 172: #define SWRITE 3 /* writing */ ! 173: ! 174: /* ! 175: * Drive Parameters - copied from ROM. ! 176: * If patched, use the given values instead of reading from the ROM. ! 177: * NOTE: Exactly duplicates hdparm_s struct. ! 178: */ ! 179: struct dparm_s { ! 180: unsigned short d_ncyl; /* number of cylinders */ ! 181: unsigned char d_nhead; /* number of heads */ ! 182: unsigned short d_rwcc; /* reduced write current cyl */ ! 183: unsigned short d_wpcc; /* write pre-compensation cyl */ ! 184: unsigned char d_eccl; /* max ecc data length */ ! 185: unsigned char d_ctrl; /* control byte */ ! 186: unsigned char d_fill2[3]; ! 187: unsigned short d_landc; /* landing zone cylinder */ ! 188: unsigned char d_nspt; /* number of sectors per track */ ! 189: unsigned char d_fill3; ! 190: ! 191: } atparm[ NDRIVE ] = { ! 192: 0 /* Initialized to allow patching */ ! 193: }; ! 194: ! 195: /* ! 196: * Partition Parameters - copied from disk. ! 197: * ! 198: * There are NDRIVE * NPARTN positions for the user partitions, ! 199: * plus NDRIVE additional partitions to span each drive. ! 200: * ! 201: * Aligning partitions on cylinder boundaries: ! 202: * Optimal partition size: 2 * 3 * 4 * 5 * 7 * 17 = 14280 blocks ! 203: * Acceptable partition size: 3 * 4 * 5 * 7 * 17 = 7140 blocks ! 204: */ ! 205: static ! 206: struct fdisk_s pparm[NDRIVE*NPARTN + NDRIVE]; ! 207: ! 208: /* ! 209: * Per disk controller data. ! 210: * Only one controller; no more, no less. ! 211: */ ! 212: static ! 213: struct at { ! 214: BUF *at_actf; /* Link to first */ ! 215: BUF *at_actl; /* Link to last */ ! 216: faddr_t at_faddr; /* Source/Dest virtual address */ ! 217: daddr_t at_bno; /* Block # on disk */ ! 218: unsigned at_nsec; /* # of sectors on current transfer */ ! 219: unsigned at_drv; ! 220: unsigned at_head; ! 221: unsigned at_cyl; ! 222: unsigned at_sec; ! 223: unsigned at_partn; ! 224: unsigned char at_dtype[ NDRIVE ]; /* drive type, 0 if unused */ ! 225: unsigned char at_tries; ! 226: unsigned char at_state; ! 227: unsigned char at_caching; /* caching in progress */ ! 228: #if ATCACHE > 0 ! 229: unsigned char at_cdrv[ ATCACHE ]; /* cached drive */ ! 230: daddr_t at_cbno[ ATCACHE ]; /* cached block number */ ! 231: unsigned char * at_cbuf[ ATCACHE ]; /* cached block */ ! 232: #endif ! 233: unsigned at_bad_drv; ! 234: unsigned at_bad_head; ! 235: unsigned at_bad_cyl; ! 236: } at; ! 237: ! 238: static BUF dbuf; /* For raw I/O */ ! 239: ! 240: /* ! 241: * Patchable variables. ! 242: * ATBSYW is a loop count for busy-waiting after issuing commands. ! 243: * ATSECS is number of seconds to wait for an expected interrupt. ! 244: */ ! 245: int ATBSYW = 50; /* patchable */ ! 246: int ATSECS = 6; /* patchable */ ! 247: static char timeout_msg[] = "at%d: TO\n"; ! 248: ! 249: /** ! 250: * ! 251: * void ! 252: * atload() - load routine. ! 253: * ! 254: * Action: The controller is reset and the interrupt vector is grabbed. ! 255: * The drive characteristics are set up at this time. ! 256: */ ! 257: static void ! 258: atload() ! 259: { ! 260: unsigned int u; ! 261: struct dparm_s * dp; ! 262: struct { unsigned off, seg; } p; ! 263: ! 264: if (n_atdr == 0) ! 265: return; ! 266: ! 267: /* ! 268: * Obtain Drive Types. ! 269: * ! 270: * High nibble of CMOS 0x12 is drive 0's type. ! 271: * Low nibble of CMOS 0x12 is drive 1's type. ! 272: */ ! 273: outb(CMOSA, 0x12); ! 274: /* delay */ ! 275: u = inb(CMOSD); ! 276: at.at_dtype[0] = u >> 4; ! 277: at.at_dtype[1] = u & 15; ! 278: ! 279: ! 280: /* ! 281: * Obtain Drive Characteristics. ! 282: */ ! 283: for (u = 0, dp = &atparm[0]; u < n_atdr; ++dp, ++u) { ! 284: struct dparm_s int_dp; ! 285: ! 286: if (dp->d_ncyl == 0) { ! 287: /* ! 288: * Not patched. ! 289: * ! 290: * If tertiary boot sent us parameters, ! 291: * Use "fifo" routines to fetch them. ! 292: * This only gives us ncyl, nhead, and nspt. ! 293: * Make educated guesses for other parameters: ! 294: * Set landc to ncyl, wpcc to -1. ! 295: * Set ctrl to 0 or 8 depending on head count. ! 296: * ! 297: * Follow INT 0x41/46 to get drive static BIOS drive ! 298: * parameters, if any. ! 299: * ! 300: * If there were no parameters from tertiary boot, ! 301: * or if INT 0x4? nhead and nspt match tboot parms, ! 302: * use "INT" parameters (will give better match on ! 303: * wpcc, landc, and ctrl fields, which tboot can't ! 304: * give us). ! 305: */ ! 306: ! 307: FIFO *ffp; ! 308: typed_space *tp; ! 309: int found, parm_int; ! 310: extern typed_space boot_gift; ! 311: ! 312: if (F_NULL != (ffp = fifo_open(&boot_gift, 0))) { ! 313: ! 314: for (found = 0; ! 315: !found && T_NULL != (tp = fifo_read(ffp)); ! 316: ) { ! 317: BIOS_DISK *bdp = (BIOS_DISK *)tp->ts_data; ! 318: if ((T_BIOS_DISK == tp->ts_type) && ! 319: (u == bdp->dp_drive) ) { ! 320: found = 1; ! 321: dp->d_ncyl = bdp->dp_cylinders; ! 322: dp->d_nhead = bdp->dp_heads; ! 323: dp->d_nspt = bdp->dp_sectors; ! 324: dp->d_wpcc = 0xffff; ! 325: dp->d_landc = dp->d_ncyl; ! 326: if (dp->d_nhead > 8) ! 327: dp->d_ctrl |= 8; ! 328: } ! 329: } ! 330: fifo_close(ffp); ! 331: } ! 332: ! 333: if (u == 0) ! 334: parm_int = 0x41; ! 335: else /* (u == 1) */ ! 336: parm_int = 0x46; ! 337: pkcopy((paddr_t)(parm_int*4), &p, sizeof p); ! 338: pkcopy((paddr_t) (p.seg << 4L) + p.off, ! 339: &int_dp, sizeof(int_dp)); ! 340: if (!found || ! 341: (dp->d_nhead == int_dp.d_nhead ! 342: && dp->d_nspt == int_dp.d_nspt)) { ! 343: *dp = int_dp; ! 344: printf("Using INT 0x%x",parm_int); ! 345: } else ! 346: printf("Using INT 0x13(08)"); ! 347: } else { ! 348: printf("Using patched"); ! 349: /* ! 350: * Avoid incomplete patching. ! 351: */ ! 352: if (at.at_dtype[u] == 0) ! 353: at.at_dtype[u] = 1; ! 354: if (dp->d_nspt == 0) ! 355: dp->d_nspt = 17; ! 356: #if FORCE_CTRL_8 ! 357: if (dp->d_nhead > 8) ! 358: dp->d_ctrl |= 8; ! 359: #endif ! 360: ! 361: } ! 362: #if VERBOSE > 0 ! 363: printf(" drive %d parameters\n", u); ! 364: printf( ! 365: "at%d: ncyl=%d nhead=%d wpcc=%d eccl=%d ctrl=%d landc=%d nspt=%d\n", ! 366: u, ! 367: dp->d_ncyl, ! 368: dp->d_nhead, ! 369: dp->d_wpcc, ! 370: dp->d_eccl, ! 371: dp->d_ctrl, ! 372: dp->d_landc, ! 373: dp->d_nspt); ! 374: #endif ! 375: } ! 376: ! 377: /* ! 378: * Initialize Drive Size. ! 379: */ ! 380: for (u = 0, dp = &atparm[0]; u < n_atdr; ++dp, ++u) { ! 381: ! 382: if (at.at_dtype[u] == 0) ! 383: continue; ! 384: ! 385: pparm[NDRIVE*NPARTN + u].p_size = ! 386: (long) dp->d_ncyl * dp->d_nhead * dp->d_nspt; ! 387: } ! 388: ! 389: /* ! 390: * Initialize Drive Controller. ! 391: */ ! 392: atreset(); ! 393: ! 394: setivec(HDIRQ, atintr); ! 395: ! 396: #if ATCACHE > 0 ! 397: at.at_cdrv[0] = -1; ! 398: at.at_cbuf[0] = kalloc(BSIZE); ! 399: #endif ! 400: ! 401: #if ATCACHE > 1 ! 402: at.at_cdrv[1] = -1; ! 403: at.at_cbuf[1] = kalloc(BSIZE); ! 404: #endif ! 405: ! 406: at.at_bad_drv = -1; ! 407: } ! 408: ! 409: /** ! 410: * ! 411: * void ! 412: * atunload() - unload routine. ! 413: */ ! 414: static void ! 415: atunload() ! 416: { ! 417: clrivec(HDIRQ); ! 418: } ! 419: ! 420: /** ! 421: * ! 422: * void ! 423: * atreset() -- reset hard disk controller, define drive characteristics. ! 424: */ ! 425: static void ! 426: atreset() ! 427: { ! 428: register int u; ! 429: register struct dparm_s * dp; ! 430: ! 431: /* ! 432: * Reset controller for a minimum of 4.8 microseconds. ! 433: */ ! 434: outb(HF_REG, 4); ! 435: for (u = 100; --u != 0;) ! 436: ; ! 437: outb(HF_REG, atparm[0].d_ctrl & 0x0F); ! 438: myatbsyw(0); ! 439: if (inb(AUX_REG) != 0x01) ! 440: printf("at: AT disk controller not present (reset)\n"); ! 441: ! 442: /* ! 443: * Initialize drive parameters. ! 444: */ ! 445: for (u = 0, dp = &atparm[0]; u < n_atdr; ++dp, ++u) { ! 446: ! 447: if (at.at_dtype[u] == 0) ! 448: continue; ! 449: ! 450: myatbsyw(u); ! 451: ! 452: /* ! 453: * Set drive characteristics. ! 454: * 0x1F1 - AUX_REG ! 455: * 0x1F2 - NSEC_REG ! 456: * 0x1F3 - SEC_REG ! 457: * 0x1F4 - LCYL_REG ! 458: * 0x1F5 - HCYL_REG ! 459: * 0x1F6 - HDRV_REG ! 460: * 0x1F7 - CSR_REG ! 461: */ ! 462: outb(HF_REG, dp->d_ctrl); ! 463: outb(AUX_REG, dp->d_wpcc / 4); ! 464: outb(NSEC_REG, dp->d_nspt); ! 465: outb(SEC_REG, 0x01); ! 466: outb(LCYL_REG, (char)(dp->d_ncyl)); ! 467: outb(HCYL_REG, (char)(dp->d_ncyl >> 8)); ! 468: outb(HDRV_REG, 0xA0 + (u<<4) + dp->d_nhead - 1); ! 469: outb(CSR_REG, SETPARM_CMD); ! 470: myatbsyw(u); ! 471: ! 472: /* ! 473: * Restore heads. ! 474: */ ! 475: outb(CSR_REG, RESTORE(0)); ! 476: myatbsyw(u); ! 477: } ! 478: } ! 479: ! 480: /** ! 481: * ! 482: * void ! 483: * atopen(dev, mode) ! 484: * dev_t dev; ! 485: * int mode; ! 486: * ! 487: * Input: dev = disk device to be opened. ! 488: * mode = access mode [IPR,IPW, IPR+IPW]. ! 489: * ! 490: * Action: Validate the minor device. ! 491: * Update the paritition table if necessary. ! 492: */ ! 493: static void ! 494: atopen(dev, mode) ! 495: register dev_t dev; ! 496: { ! 497: register int d; /* drive */ ! 498: register int p; /* partition */ ! 499: ! 500: p = minor(dev) % (NDRIVE*NPARTN); ! 501: ! 502: if (minor(dev) & SDEV) { ! 503: d = minor(dev) % NDRIVE; ! 504: p += NDRIVE * NPARTN; ! 505: } ! 506: else ! 507: d = minor(dev) / NPARTN; ! 508: ! 509: if ((d >= NDRIVE) || (at.at_dtype[d] == 0)) { ! 510: u.u_error = ENXIO; ! 511: return; ! 512: } ! 513: ! 514: if (minor(dev) & SDEV) ! 515: return; ! 516: ! 517: /* ! 518: * If partition not defined read partition characteristics. ! 519: */ ! 520: if (pparm[p].p_size == 0) ! 521: fdisk(makedev(major(dev), SDEV + d), &pparm[ d * NPARTN ]); ! 522: ! 523: /* ! 524: * Ensure partition lies within drive boundaries and is non-zero size. ! 525: */ ! 526: if ((pparm[p].p_base+pparm[p].p_size) > pparm[d+NDRIVE*NPARTN].p_size) ! 527: u.u_error = EBADFMT; ! 528: else if (pparm[p].p_size == 0) ! 529: u.u_error = ENODEV; ! 530: } ! 531: ! 532: /** ! 533: * ! 534: * void ! 535: * atread(dev, iop) - write a block to the raw disk ! 536: * dev_t dev; ! 537: * IO * iop; ! 538: * ! 539: * Input: dev = disk device to be written to. ! 540: * iop = pointer to source I/O structure. ! 541: * ! 542: * Action: Invoke the common raw I/O processing code. ! 543: */ ! 544: static void ! 545: atread(dev, iop) ! 546: dev_t dev; ! 547: IO *iop; ! 548: { ! 549: ioreq(&dbuf, iop, dev, BREAD, BFRAW|BFBLK|BFIOC); ! 550: } ! 551: ! 552: /** ! 553: * ! 554: * void ! 555: * atwrite(dev, iop) - write a block to the raw disk ! 556: * dev_t dev; ! 557: * IO * iop; ! 558: * ! 559: * Input: dev = disk device to be written to. ! 560: * iop = pointer to source I/O structure. ! 561: * ! 562: * Action: Invoke the common raw I/O processing code. ! 563: */ ! 564: static void ! 565: atwrite(dev, iop) ! 566: dev_t dev; ! 567: IO *iop; ! 568: { ! 569: ioreq(&dbuf, iop, dev, BWRITE, BFRAW|BFBLK|BFIOC); ! 570: } ! 571: ! 572: /** ! 573: * ! 574: * int ! 575: * atioctl(dev, cmd, arg) ! 576: * dev_t dev; ! 577: * int cmd; ! 578: * char * vec; ! 579: * ! 580: * Input: dev = disk device to be operated on. ! 581: * cmd = input/output request to be performed. ! 582: * vec = (pointer to) optional argument. ! 583: * ! 584: * Action: Validate the minor device. ! 585: * Update the paritition table if necessary. ! 586: */ ! 587: static int ! 588: atioctl(dev, cmd, vec) ! 589: register dev_t dev; ! 590: int cmd; ! 591: char * vec; ! 592: { ! 593: int d; ! 594: ! 595: /* ! 596: * Identify drive number. ! 597: */ ! 598: if (minor(dev) & SDEV) ! 599: d = minor(dev) % NDRIVE; ! 600: else ! 601: d = minor(dev) / NPARTN; ! 602: ! 603: /* ! 604: * Identify input/output request. ! 605: */ ! 606: switch (cmd) { ! 607: ! 608: case HDGETA: ! 609: /* ! 610: * Get hard disk attributes. ! 611: */ ! 612: kucopy(&atparm[d], vec, sizeof(atparm[0])); ! 613: return(0); ! 614: ! 615: case HDSETA: ! 616: /* Set hard disk attributes. */ ! 617: ukcopy(vec, &atparm[d], sizeof(atparm[0])); ! 618: at.at_dtype[d] = 1; /* set drive type nonzero */ ! 619: pparm[NDRIVE * NPARTN + d].p_size = ! 620: (long) atparm[d].d_ncyl * atparm[d].d_nhead * atparm[d].d_nspt; ! 621: atreset(); ! 622: return 0; ! 623: ! 624: default: ! 625: u.u_error = EINVAL; ! 626: return(-1); ! 627: } ! 628: } ! 629: ! 630: /** ! 631: * ! 632: * void ! 633: * atwatch() - guard against lost interrupt ! 634: * ! 635: * Action: If drvl[AT_MAJOR] is greater than zero, decrement it. ! 636: * If it decrements to zero, simulate a hardware interrupt. ! 637: */ ! 638: static void ! 639: atwatch() ! 640: { ! 641: register BUF * bp = at.at_actf; ! 642: register int s; ! 643: ! 644: s = sphi(); ! 645: if (--drvl[AT_MAJOR].d_time > 0) { ! 646: spl(s); ! 647: return; ! 648: } ! 649: printf("at%d%c: bno=%U head=%u cyl=%u <Watchdog Timeout>\n", ! 650: at.at_drv, ! 651: (bp->b_dev & SDEV) ? 'x' : at.at_partn % NPARTN + 'a', ! 652: bp->b_bno, at.at_head, at.at_cyl); ! 653: ! 654: /* ! 655: * Reset hard disk controller. ! 656: * ! 657: * Mark current cylinder as bad so atstart() will fail. ! 658: * Otherwise would lock up if this track NEVER gives enough IRQ's. ! 659: */ ! 660: at.at_bad_drv = at.at_drv; ! 661: at.at_bad_head = at.at_head; ! 662: at.at_bad_cyl = at.at_cyl; ! 663: atreset(); ! 664: atstart(); ! 665: spl(s); ! 666: } ! 667: ! 668: /** ! 669: * ! 670: * void ! 671: * atblock(bp) - queue a block to the disk ! 672: * ! 673: * Input: bp = pointer to block to be queued. ! 674: * ! 675: * Action: Queue a block to the disk. ! 676: * Make sure that the transfer is within the disk partition. ! 677: */ ! 678: static void ! 679: atblock(bp) ! 680: register BUF *bp; ! 681: { ! 682: register struct fdisk_s *pp; ! 683: int partn = minor(bp->b_dev) % (NDRIVE*NPARTN); ! 684: ! 685: bp->b_resid = bp->b_count; ! 686: ! 687: if (minor(bp->b_dev) & SDEV) ! 688: partn += NDRIVE * NPARTN; ! 689: ! 690: pp = &pparm[ partn ]; ! 691: ! 692: /* ! 693: * Check for read at end of partition. ! 694: */ ! 695: if ((bp->b_req == BREAD) && (bp->b_bno == pp->p_size)) { ! 696: bdone(bp); ! 697: return; ! 698: } ! 699: ! 700: /* ! 701: * Range check disk region. ! 702: */ ! 703: if (((bp->b_bno + (bp->b_count/BSIZE)) > pp->p_size) ! 704: || (bp->b_count % BSIZE) || bp->b_count == 0) { ! 705: bp->b_flag |= BFERR; ! 706: bdone(bp); ! 707: return; ! 708: } ! 709: ! 710: bp->b_actf = NULL; ! 711: if (at.at_actf == NULL) ! 712: at.at_actf = bp; ! 713: else ! 714: at.at_actl->b_actf = bp; ! 715: at.at_actl = bp; ! 716: ! 717: if (at.at_state == SIDLE) ! 718: if (atdequeue()) ! 719: atstart(); ! 720: } ! 721: ! 722: /** ! 723: * ! 724: * int ! 725: * atdequeue() - obtain next disk read/write operation ! 726: * ! 727: * Action: Pull some work from the disk queue. ! 728: * ! 729: * Return: 0 = no work. ! 730: * * = work to do. ! 731: */ ! 732: static int ! 733: atdequeue() ! 734: { ! 735: register BUF * bp; ! 736: register struct fdisk_s * pp; ! 737: unsigned int nspt; ! 738: ! 739: for (;;) { ! 740: at.at_caching = 0; ! 741: at.at_tries = 0; ! 742: ! 743: if ((bp = at.at_actf) == NULL) ! 744: return (0); ! 745: ! 746: at.at_partn = minor(bp->b_dev) % (NDRIVE*NPARTN); ! 747: ! 748: if (minor(bp->b_dev) & SDEV) { ! 749: at.at_partn += (NDRIVE*NPARTN); ! 750: at.at_drv = minor(bp->b_dev) % NDRIVE; ! 751: } ! 752: else ! 753: at.at_drv = minor(bp->b_dev) / NPARTN; ! 754: nspt = atparm[at.at_drv].d_nspt; ! 755: ! 756: pp = &pparm[ at.at_partn ]; ! 757: at.at_bno = pp->p_base + bp->b_bno; ! 758: at.at_nsec = bp->b_count / BSIZE; ! 759: at.at_faddr = bp->b_faddr; ! 760: ! 761: #if ATCACHE > 0 ! 762: if (bp->b_req == BWRITE) { ! 763: ! 764: /* ! 765: * Invalidate cache if write might overlap. ! 766: */ ! 767: if (at.at_nsec > 1) { ! 768: at.at_cdrv[0] = -1; ! 769: #if ATCACHE > 1 ! 770: at.at_cdrv[1] = -1; ! 771: #endif ! 772: } ! 773: else if (at.at_bno == at.at_cbno[0]) ! 774: at.at_cdrv[0] = -1; ! 775: #if ATCACHE > 1 ! 776: else if (at.at_bno == at.at_cbno[1]) ! 777: at.at_cdrv[1] = -1; ! 778: #endif ! 779: } ! 780: else if (at.at_nsec == 1) { ! 781: ! 782: /* ! 783: * Test for cache hit on block 0. ! 784: */ ! 785: if ((at.at_drv == at.at_cdrv[0]) ! 786: && (at.at_bno == at.at_cbno[0])) { ! 787: ! 788: kpcopy(at.at_cbuf[0], ! 789: bp->b_paddr, BSIZE); ! 790: at.at_actf = bp->b_actf; ! 791: bp->b_resid = 0; ! 792: bdone(bp); ! 793: continue; ! 794: } ! 795: ! 796: #if ATCACHE > 1 ! 797: /* ! 798: * Test for cache hit on block 1. ! 799: */ ! 800: if ((at.at_drv == at.at_cdrv[1]) ! 801: && (at.at_bno == at.at_cbno[1])) { ! 802: ! 803: kpcopy(at.at_cbuf[1], ! 804: bp->b_paddr, BSIZE); ! 805: at.at_actf = bp->b_actf; ! 806: bp->b_resid = 0; ! 807: bdone(bp); ! 808: continue; ! 809: } ! 810: #endif ! 811: ! 812: /* ! 813: * Enable caching if no backlog for disk i/o. ! 814: */ ! 815: if (bp->b_actf == NULL) { ! 816: /* ! 817: * Enable caching on single block reads ! 818: * when at least one block left on same track. ! 819: */ ! 820: at.at_caching = nspt - 1 - (at.at_bno % nspt); ! 821: #if ATCACHE > 1 ! 822: if (at.at_caching >= 2) { ! 823: at.at_caching = 2; ! 824: at.at_cdrv[2-1] = -1; ! 825: } ! 826: #endif ! 827: ! 828: if (at.at_caching) { ! 829: at.at_nsec += at.at_caching; ! 830: at.at_cdrv[1-1] = -1; ! 831: } ! 832: } ! 833: } ! 834: #endif ! 835: ! 836: return (1); ! 837: } ! 838: } ! 839: ! 840: /** ! 841: * ! 842: * void ! 843: * atstart() - start or restart next disk read/write operation. ! 844: * ! 845: * Action: Initiate disk read/write operation. ! 846: */ ! 847: static void ! 848: atstart() ! 849: { ! 850: register struct dparm_s *dp; ! 851: ! 852: dp = &atparm[ at.at_drv ]; ! 853: ! 854: at.at_cyl = (at.at_bno / dp->d_nspt) / dp->d_nhead; ! 855: at.at_head = (at.at_bno / dp->d_nspt) % dp->d_nhead; ! 856: at.at_sec = (at.at_bno % dp->d_nspt) + 1; ! 857: ! 858: /* ! 859: * Check for repeated access to most recently identified bad track. ! 860: */ ! 861: if ((at.at_drv == at.at_bad_drv) ! 862: && (at.at_cyl == at.at_bad_cyl) ! 863: && (at.at_head == at.at_bad_head)) { ! 864: BUF * bp = at.at_actf; ! 865: printf("at%d%c: bno=%U head=%u cyl=%u <Track Flagged Bad>\n", ! 866: at.at_drv, ! 867: (bp->b_dev & SDEV) ? 'x' : at.at_partn % NPARTN + 'a', ! 868: bp->b_bno, ! 869: at.at_head, ! 870: at.at_cyl); ! 871: bp->b_flag |= BFERR; ! 872: atdone(bp); ! 873: return; ! 874: } ! 875: ! 876: myatbsyw(at.at_drv); ! 877: ! 878: outb(HF_REG, dp->d_ctrl); ! 879: outb(AUX_REG, dp->d_wpcc / 4); ! 880: outb(NSEC_REG, at.at_nsec); ! 881: outb(SEC_REG, at.at_sec); ! 882: outb(LCYL_REG, at.at_cyl); ! 883: outb(HCYL_REG, at.at_cyl >> 8); ! 884: outb(HDRV_REG, (at.at_drv << 4) + at.at_head + 0xA0); ! 885: ! 886: if (at.at_actf->b_req == BWRITE) { ! 887: ! 888: outb(CSR_REG, WRITE_CMD); ! 889: ! 890: while (atdrqw() == 0) ! 891: printf(timeout_msg, at.at_drv); ! 892: ! 893: atsend(at.at_faddr); ! 894: at.at_state = SWRITE; ! 895: } ! 896: else { ! 897: outb(CSR_REG, READ_CMD); ! 898: at.at_state = SREAD; ! 899: } ! 900: drvl[AT_MAJOR].d_time = ATSECS; ! 901: } ! 902: ! 903: /** ! 904: * ! 905: * void ! 906: * atintr() - Interrupt routine. ! 907: * ! 908: * Clear interrupt then defer actual processing. ! 909: */ ! 910: static void ! 911: atintr() ! 912: { ! 913: inb(CSR_REG); /* clears controller interrupt */ ! 914: defer(atdefer, 0); ! 915: } ! 916: ! 917: /** ! 918: * ! 919: * void ! 920: * atdefer() - Deferred service of hard disk interrupt. ! 921: * ! 922: * Action: Service disk interrupt. ! 923: * Transfer required data. ! 924: * Update state. ! 925: */ ! 926: static void ! 927: atdefer() ! 928: { ! 929: register BUF * bp = at.at_actf; ! 930: ! 931: switch (at.at_state) { ! 932: ! 933: case SRETRY: ! 934: atstart(); ! 935: break; ! 936: ! 937: case SREAD: ! 938: /* ! 939: * Check for I/O error before waiting for data. ! 940: */ ! 941: if (aterror()) { ! 942: atrecov(); ! 943: break; ! 944: } ! 945: ! 946: /* ! 947: * Wait for data, or forever. ! 948: */ ! 949: if (atdrqw() == 0) ! 950: printf(timeout_msg, at.at_drv); ! 951: ! 952: #if ATCACHE > 0 ! 953: /* ! 954: * Cache data block. ! 955: */ ! 956: if (at.at_caching == at.at_nsec) ! 957: atrecv(at.at_cbuf[ at.at_nsec - 1 ], sds); ! 958: else ! 959: #endif ! 960: ! 961: /* ! 962: * Read data block. ! 963: */ ! 964: atrecv(at.at_faddr); ! 965: ! 966: /* ! 967: * Check for I/O error after reading data. ! 968: */ ! 969: if (aterror()) { ! 970: atrecov(); ! 971: break; ! 972: } ! 973: ! 974: #if ATCACHE > 0 ! 975: /* ! 976: * Validate cached blocks. ! 977: */ ! 978: if (at.at_caching == at.at_nsec) { ! 979: at.at_cbno[ at.at_nsec - 1 ] = at.at_bno; ! 980: at.at_cdrv[ at.at_nsec - 1 ] = at.at_drv; ! 981: at.at_caching--; ! 982: } ! 983: else ! 984: #endif ! 985: { ! 986: FP_OFF(at.at_faddr) += BSIZE; ! 987: bp->b_resid -= BSIZE; ! 988: } ! 989: ! 990: at.at_tries = 0; ! 991: at.at_bno++; ! 992: ! 993: /* ! 994: * Check for end of transfer. ! 995: */ ! 996: if (--at.at_nsec == 0) ! 997: atdone(bp); ! 998: break; ! 999: ! 1000: case SWRITE: ! 1001: /* ! 1002: * Check for I/O error. ! 1003: */ ! 1004: if (aterror()) { ! 1005: atrecov(); ! 1006: break; ! 1007: } ! 1008: ! 1009: FP_OFF(at.at_faddr) += BSIZE; ! 1010: bp->b_resid -= BSIZE; ! 1011: at.at_tries = 0; ! 1012: at.at_bno++; ! 1013: ! 1014: /* ! 1015: * Check for end of transfer. ! 1016: */ ! 1017: if (--at.at_nsec == 0) { ! 1018: atdone(bp); ! 1019: break; ! 1020: } ! 1021: ! 1022: /* ! 1023: * Wait for ability to send data, or forever. ! 1024: */ ! 1025: while (atdrqw() == 0) ! 1026: printf(timeout_msg, at.at_drv); ! 1027: ! 1028: /* ! 1029: * Send data block. ! 1030: */ ! 1031: atsend(at.at_faddr); ! 1032: } ! 1033: } ! 1034: ! 1035: /** ! 1036: * ! 1037: * int ! 1038: * aterror() ! 1039: * ! 1040: * Action: Check for drive error. ! 1041: * If found, increment error count and report it. ! 1042: * ! 1043: * Return: 0 = No error found. ! 1044: * 1 = Error occurred. ! 1045: */ ! 1046: static int ! 1047: aterror() ! 1048: { ! 1049: register BUF * bp = at.at_actf; ! 1050: register int csr; ! 1051: register int aux; ! 1052: ! 1053: if ((csr = inb(HF_REG)) & (ERR_ST|WFLT_ST)) { ! 1054: ! 1055: aux = inb(AUX_REG); ! 1056: ! 1057: /* ! 1058: * Don't retry or report failures on cache reads. ! 1059: */ ! 1060: #if ATCACHE > 0 ! 1061: if ((at.at_state == SREAD) && (at.at_caching == at.at_nsec)) { ! 1062: at.at_tries = BADLIM; ! 1063: return 1; ! 1064: } ! 1065: #endif ! 1066: ! 1067: if (aux & BAD_ERR) { ! 1068: at.at_tries = BADLIM; ! 1069: at.at_bad_drv = at.at_drv; ! 1070: at.at_bad_head = at.at_head; ! 1071: at.at_bad_cyl = at.at_cyl; ! 1072: } ! 1073: else if (++at.at_tries < SOFTLIM) ! 1074: return 1; ! 1075: ! 1076: printf("at%d%c: bno=%U head=%u cyl=%u", ! 1077: at.at_drv, ! 1078: (bp->b_dev & SDEV) ? 'x' : at.at_partn % NPARTN + 'a', ! 1079: (bp->b_count/BSIZE) + bp->b_bno ! 1080: + at.at_caching - at.at_nsec, ! 1081: at.at_head, at.at_cyl); ! 1082: ! 1083: #if VERBOSE > 0 ! 1084: if ((csr & RDY_ST) == 0) ! 1085: printf(" <Drive Not Ready>"); ! 1086: if (csr & WFLT_ST) ! 1087: printf(" <Write Fault>"); ! 1088: ! 1089: if (aux & DAM_ERR) ! 1090: printf(" <No Data Addr Mark>"); ! 1091: if (aux & TR0_ERR) ! 1092: printf(" <Track 0 Not Found>"); ! 1093: if (aux & ID_ERR) ! 1094: printf(" <ID Not Found>"); ! 1095: if (aux & ECC_ERR) ! 1096: printf(" <Bad Data Checksum>"); ! 1097: if (aux & ABT_ERR) ! 1098: printf(" <Command Aborted>"); ! 1099: #else ! 1100: if ((csr & (RDY_ST|WFLT_ST)) != RDY_ST) ! 1101: printf(" csr=%x", csr); ! 1102: if (aux & (DAM_ERR|TR0_ERR|ID_ERR|ECC_ERR|ABT_ERR)) ! 1103: printf(" aux=%x", aux); ! 1104: #endif ! 1105: if (aux & BAD_ERR) ! 1106: printf(" <Block Flagged Bad>"); ! 1107: ! 1108: if (at.at_tries < HARDLIM) ! 1109: printf(" retrying..."); ! 1110: printf("\n"); ! 1111: return 1; ! 1112: } ! 1113: return 0; ! 1114: } ! 1115: ! 1116: /** ! 1117: * ! 1118: * void ! 1119: * atrecov() ! 1120: * ! 1121: * Action: Attempt recovery. ! 1122: */ ! 1123: static void ! 1124: atrecov() ! 1125: { ! 1126: register BUF *bp = at.at_actf; ! 1127: register int cmd = SEEK(0); ! 1128: register int cyl = at.at_cyl; ! 1129: ! 1130: switch (at.at_tries) { ! 1131: ! 1132: case 1: ! 1133: case 2: ! 1134: /* ! 1135: * Move in 1 cylinder, then retry operation ! 1136: */ ! 1137: if (--cyl < 0) ! 1138: cyl += 2; ! 1139: break; ! 1140: ! 1141: case 3: ! 1142: case 4: ! 1143: /* ! 1144: * Move out 1 cylinder, then retry operation ! 1145: */ ! 1146: if (++cyl >= atparm[ at.at_drv ].d_ncyl) ! 1147: cyl -= 2; ! 1148: break; ! 1149: ! 1150: case 5: ! 1151: case 6: ! 1152: /* ! 1153: * Seek to cylinder 0, then retry operation ! 1154: */ ! 1155: cyl = 0; ! 1156: break; ! 1157: ! 1158: default: ! 1159: /* ! 1160: * Restore drive, then retry operation ! 1161: */ ! 1162: cmd = RESTORE(0); ! 1163: cyl = 0; ! 1164: break; ! 1165: } ! 1166: ! 1167: /* ! 1168: * Retry operation [after repositioning head] ! 1169: */ ! 1170: if (at.at_tries < HARDLIM) { ! 1171: drvl[AT_MAJOR].d_time = (cmd == RESTORE(0)) ! 1172: ? (ATSECS * 2) : ATSECS; ! 1173: outb(LCYL_REG, cyl); ! 1174: outb(HCYL_REG, cyl >> 8); ! 1175: outb(HDRV_REG, (at.at_drv << 4) + 0xA0); ! 1176: outb(CSR_REG, cmd); ! 1177: at.at_state = SRETRY; ! 1178: } ! 1179: ! 1180: /* ! 1181: * Give up on block. ! 1182: */ ! 1183: else { ! 1184: /* ! 1185: * Not a cache-read error. ! 1186: */ ! 1187: #if ATCACHE > 0 ! 1188: if ((at.at_state != SREAD) || (at.at_caching != at.at_nsec)) ! 1189: #endif ! 1190: bp->b_flag |= BFERR; ! 1191: ! 1192: atdone(bp); ! 1193: } ! 1194: } ! 1195: ! 1196: /** ! 1197: * ! 1198: * void ! 1199: * atdone(bp) ! 1200: * BUF * bp; ! 1201: * ! 1202: * Action: Release current i/o buffer to the O/S. ! 1203: */ ! 1204: static void ! 1205: atdone(bp) ! 1206: register BUF * bp; ! 1207: { ! 1208: drvl[AT_MAJOR].d_time = 0; ! 1209: at.at_state = SIDLE; ! 1210: at.at_actf = bp->b_actf; ! 1211: bdone(bp); ! 1212: ! 1213: if (atdequeue()) ! 1214: atstart(); ! 1215: } ! 1216: ! 1217: int ! 1218: myatbsyw(unit) int unit; ! 1219: { ! 1220: register int n, status; ! 1221: ! 1222: for (n = ATBSYW; n > 0; --n) ! 1223: if ((status = atbsyw()) != 0) ! 1224: return status; ! 1225: printf(timeout_msg, unit); ! 1226: return 0; ! 1227: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.