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