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