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