|
|
1.1 ! root 1: /* ! 2: * File: fl386.c ! 3: * ! 4: * Purpose: Diskette device control. ! 5: * Requires 765 controller module fdc.c ! 6: * ! 7: * Revised: Wed May 5 11:23:53 1993 CDT ! 8: * Modified: 7/93 - autosensing and track 0 skips for iBCS2 ! 9: * complianacy and greater compatibility - CA8 ! 10: */ ! 11: ! 12: /* ! 13: * Minor device assignments: xxuuhkkk ! 14: * uu - unit = 0/1/2/3 ! 15: * kkk - kind, struct fdata infra. ! 16: * h - alternating head rather than side by side ! 17: * xx - 0=diskette 1=floppy tape ! 18: */ ! 19: ! 20: /* ! 21: * ---------------------------------------------------------------------- ! 22: * Includes. ! 23: */ ! 24: #include <sys/coherent.h> ! 25: ! 26: #include <sys/errno.h> ! 27: #include <sys/buf.h> ! 28: #include <sys/con.h> ! 29: #include <sys/dmac.h> ! 30: #include <sys/devices.h> ! 31: #include <sys/fdc765.h> ! 32: #include <sys/fdioctl.h> ! 33: #include <sys/file.h> ! 34: #include <sys/sched.h> ! 35: #include <sys/stat.h> ! 36: ! 37: /* ! 38: * ---------------------------------------------------------------------- ! 39: * Definitions. ! 40: * Constants. ! 41: * Macros with argument lists. ! 42: * Typedefs. ! 43: * Enums. ! 44: */ ! 45: ! 46: #define MAXDRVS 2 /* Maximum number of drives that we will support */ ! 47: #define MAXSCTRS 21 /* Maximum acceptable sectors per track. It is */ ! 48: /* possible to put as many as 10 sectors/track */ ! 49: /* on low density diskettes, 18 sectors/track on */ ! 50: /* 5 1/4" high-density diskettes, and 21 sectors */ ! 51: /* per track on 3 1/2" high density diskettes. */ ! 52: /* the maximum on "2.88" meg diskettes is not */ ! 53: /* known as of this writing, but may be as high */ ! 54: /* as 42. */ ! 55: #define MAXTYPE 4 /* Maximum "type" value as set in the CMOS RAM. */ ! 56: /* The current value of this is 4, the type for */ ! 57: /* 1.44 meg diskettes. */ ! 58: ! 59: #ifdef FL_XTRA ! 60: /* This is conditioned out for now due to end-of-volume problems. */ ! 61: #define FL_CYL_2STEP 42 ! 62: #define FL_CYL_HDLO 82 ! 63: #define FL_CYL_HDHI 83 ! 64: #else ! 65: #define FL_CYL_2STEP 40 ! 66: #define FL_CYL_HDLO 80 ! 67: #define FL_CYL_HDHI 80 ! 68: #endif ! 69: ! 70: #define MTIMER 2 /* Motor timeout (seconds) */ ! 71: ! 72: /* ! 73: * Driver States. ! 74: */ ! 75: #define SIDLE 0 /* Idle */ ! 76: #define SSEEK 1 /* Need seek */ ! 77: #define SRDWR 2 /* Need read/write command */ ! 78: #define SENDIO 3 /* Need end I/O processing */ ! 79: #define SDELAY 4 /* Delay before next disk operation */ ! 80: #define SHDLY 5 /* Head settling delay before r/w */ ! 81: #define SLOCK 6 /* Got DMA controller lock */ ! 82: #define SRECAL1 7 /* First recalibrate attempt */ ! 83: #define SRECAL2 8 /* Try seeking to track 2 */ ! 84: #define SRECAL3 9 /* Second recalibrate, if necessary */ ! 85: #define SGOTO2 10 /* After seek to cylinder 2 */ ! 86: #define SRDID 11 /* Get sector ID from FDC */ ! 87: #define SSIDTST 12 /* Testing # of sides */ ! 88: ! 89: #define funit(x) (minor(x) >> 4) /* Unit/drive number */ ! 90: #define fkind(x) (minor(x) & 0x7) /* Kind of format */ ! 91: /* ! 92: * From this point on, we will only support head-by-head attempts. ! 93: * This is left here in original form as a comment in case something ! 94: * breaks and it needs to be changed back. Should eventually be ! 95: * removed altogether. This was done because bit position 3 (2^3) ! 96: * is now used to designate a special device - louis 7/93 ! 97: */ ! 98: /* #define fhbyh(x) (minor(x) & 0x8) */ /* 0=Side by side, 1=Head by head */ ! 99: #define fhbyh(x) 1 /* Always true from now on */ ! 100: #define fisspecial(x) (!(minor(x) & 0x8)) /* if bit zero special device */ ! 101: /* All special devices skip cylinder 0 except type 1; no normal devices skip */ ! 102: #define fskip_cyl_0(x) (fisspecial(x) && (fkind(x) != 1)) ! 103: /* Only special device types 0 and 1 are autosensing */ ! 104: #define fautosense(x) (fisspecial(x) && ((fkind(x) == 0) || (fkind(x) == 1))) ! 105: ! 106: struct FDATA { ! 107: int fd_size; /* Blocks per diskette */ ! 108: int fd_nhds; /* Heads per drive */ ! 109: int fd_trks; /* Tracks per side */ ! 110: int fd_offs; /* Sector base */ ! 111: int fd_nspt; /* Sectors per track */ ! 112: char fd_GPL[4]; /* Controller gap param (indexed by rate) */ ! 113: char fd_N; /* Controller size param */ ! 114: char fd_FGPL; /* Format gap length */ ! 115: }; ! 116: ! 117: struct FRATES { ! 118: char fl_hi_kind; /* "fdata" initial try for hi dens. */ ! 119: char fl_hi_rate; /* -1 here for lo-dens. */ ! 120: char fl_lo_kind; /* Lo-dens "fdata" entry to try 1st.*/ ! 121: char fl_lo_rate; /* Proper lo-density rate for type. */ ! 122: char dflt_kind; /* Default parameters. */ ! 123: char dflt_rate; /* Default data rate. */ ! 124: }; ! 125: ! 126: #define FL_NUM_DRV_STAT 2 ! 127: ! 128: struct FL { ! 129: BUF *fl_actf; /* Queue, forward */ ! 130: BUF *fl_actl; /* Queue, backward */ ! 131: paddr_t fl_addr; /* Address */ ! 132: int fl_nsec; /* # of sectors */ ! 133: int fl_secn; /* Current sector */ ! 134: struct FDATA fl_fd[MAXDRVS]; /* Disk kind data */ ! 135: int fl_fcyl; /* Floppy cylinder # */ ! 136: int fl_2step[MAXDRVS]; /* =1 for double-stepping */ ! 137: char fl_incal[MAXDRVS]; /* Disk in cal flags and current cyl */ ! 138: char fl_dsk_chngd[MAXDRVS]; /* Diskette changed flags */ ! 139: char fl_ndsk; /* # of drives */ ! 140: char fl_unit; /* Current unit # */ ! 141: char fl_selected_unit; /* Last unit selected */ ! 142: char fl_mask; /* Handy unit mask */ ! 143: char fl_hbyh; /* 0/1 = Side by side/Head by head */ ! 144: char fl_nerr; /* Error count */ ! 145: int fl_ndrvstat; /* Number of drv status bytes read */ ! 146: char fl_drvstat[FL_NUM_DRV_STAT]; /* Drive Status buffer */ ! 147: int fl_fsec; /* Floppy sector # */ ! 148: int fl_head; /* Floppy head */ ! 149: char fl_state; /* Processing state */ ! 150: char fl_mstatus; /* Motor status */ ! 151: char fl_time[MAXDRVS]; /* Motor timeout */ ! 152: char fl_rate[MAXDRVS]; /* Data rate: 500,300,250,?? kbps */ ! 153: char fl_type[MAXDRVS]; /* Type of drive: 2 = HiCap */ ! 154: char fl_rate_set; /* Currently set data rate */ ! 155: int fl_wflag; /* Write operation */ ! 156: int fl_recov; /* Recovery initiated */ ! 157: int fl_opct[MAXDRVS]; /* open count for each unit */ ! 158: int fl_we[MAXDRVS]; /* write enable for each unit */ ! 159: }; ! 160: ! 161: /* ! 162: * ---------------------------------------------------------------------- ! 163: * Functions. ! 164: * Import Functions. ! 165: * Export Functions. ! 166: * Local Functions. ! 167: */ ! 168: int nulldev(); ! 169: ! 170: static int flload(); ! 171: static int flunload(); ! 172: static int flopen(); ! 173: static int flclose(); ! 174: static int flblock(); ! 175: static int flread(); ! 176: static int flwrite(); ! 177: static int flioctl(); ! 178: static int fltimeout(); ! 179: ! 180: static void flfsm(); ! 181: ! 182: static void flQhang(); ! 183: static void clrQ(); ! 184: static void fldelay(); ! 185: static void fldone(); ! 186: static int flrate(); ! 187: static void flrecov(); ! 188: static void flIntHandler(); ! 189: static void flDrvSelect(); ! 190: static void flDrvStatus(); ! 191: ! 192: /* ! 193: * ---------------------------------------------------------------------- ! 194: * Global Data. ! 195: * Import Variables. ! 196: * Export Variables. ! 197: * Local Variables. ! 198: */ ! 199: ! 200: /* Configurable variables - see /etc/conf/fd/Space.c. */ ! 201: ! 202: extern int fl_dsk_ch_prob; ! 203: extern int fl_auto_parm; ! 204: extern int fl_disp; ! 205: ! 206: int jopen; ! 207: ! 208: /* ! 209: Here's the problem. We need to be able to tell if the disk has been changed. ! 210: There is an i/o port we can read, but on some systems, we can get constant ! 211: false positives. This causes massive floppy slowdown as the disk is constantly ! 212: recalibrating. The solution is not completely satisfactory, but it's the best ! 213: one I could come up with. Basically, what I said was since we can't tell when ! 214: the disk has changed, we will act as if it has changed every time we do an ! 215: open or a reset. The code ! 216: ! 217: if (fl_dsk_ch_prob) ! 218: jopen = 2; ! 219: ! 220: indicates the need to pretend that the disk has changed. It is set to 2 since ! 221: there are two parts to the change procedure. Additional code dependent on ! 222: the value of fl_dsk_ch_prob says that if we have not just down an open, then ! 223: we should skip the recal. Otherwise, decrement the counter, and do the ! 224: recal. - mlk */ ! 225: ! 226: /* Parameters for each kind of format */ ! 227: struct FDATA fdata[] = { ! 228: /* 8 sectors per track, surface by surface seek. */ ! 229: { 320,1,40,0, 8, { 0x00,0x20,0x20 }, 2,0x58 }, /* Single sided */ ! 230: { 640,2,40,0, 8, { 0x00,0x20,0x20 }, 2,0x58 }, /* Double sided */ ! 231: { 1280,2,80,0, 8, { 0x00,0x20,0x20 }, 2,0x58 }, /* Quad density */ ! 232: /* 9 sectors per track, surface by surface seek. */ ! 233: { 360,1,40,0, 9, { 0x00,0x20,0x20 }, 2,0x50 }, /* Single sided */ ! 234: { 720,2,40,0, 9, { 0x00,0x20,0x20 }, 2,0x50 }, /* Double sided */ ! 235: { 1440,2,80,0, 9, { 0x00,0x20,0x20 }, 2,0x50 }, /* Quad density */ ! 236: /* 15 sectors per track, surface by surface seek. */ ! 237: { 2400,2,80,0,15, { 0x1B,0x00,0x00 }, 2,0x54 }, /* High capacity */ ! 238: /* 18 sectors per track, surface by surface seek. */ ! 239: { 2880,2,80,0,18, { 0x1B,0x00,0x00 }, 2,0x6C } /* 1.44 3.5" */ ! 240: }; ! 241: ! 242: /* Parameters for each device type */ ! 243: struct FRATES frates[] = { ! 244: { 4,-1, 4,-1, 4, FDC_RATE_250K }, /* Type 0 = no drive */ ! 245: { 4,-1, 4, 2, 4, FDC_RATE_250K }, /* Type 1 = 360K */ ! 246: { 6, 0, 4, 1, 6, FDC_RATE_500K }, /* Type 2 = 1.2M */ ! 247: { 4,-1, 5, 2, 5, FDC_RATE_250K }, /* Type 3 = 720K */ ! 248: { 7, 0, 5, 2, 7, FDC_RATE_500K } /* Type 4 = 1.44M */ ! 249: }; ! 250: ! 251: struct FL fl; ! 252: ! 253: /* ! 254: * We need some areas in global RAM to use as BUF structures ! 255: * and as data areas for special functions such as formatting, ! 256: * reading the drive status and reading sector IDs. There is ! 257: * one set for each drive. When the blocks for a drive are in ! 258: * use, the "drv_locked" char is set to non-zero, and is ! 259: * cleared otherwise. While this scheme doesn't provide ! 260: * complete reentrancy, it does allow both drives to be used ! 261: * "at once" by separate tasks. ! 262: */ ! 263: char drv_locked[MAXDRVS]; /* One for each possible drive */ ! 264: char sw3[MAXDRVS]; ! 265: BUF flbuf[MAXDRVS]; ! 266: ! 267: /* ! 268: * These next items are related to the floppy disk system ! 269: * in general, so we only need one of each. ! 270: */ ! 271: TIM fltim; ! 272: TIM fldmalck; /* DMA lock deferred function structure. */ ! 273: char fl_clrng_cd; ! 274: char fl_intlv_ct, /* Counts sectors to find interleave. */ ! 275: fl_get_intlv, /* =1 to start search for interleave. */ ! 276: fl_lk4_id, /* Sector ID to look for for interleave. */ ! 277: fl_alt_kind, /* Alternate disk parameter index and */ ! 278: fl_alt_rate, /* data rate to use if not first value. */ ! 279: fl_1st_ID, /* Detects when all track sectors scanned*/ ! 280: fl_hi_ID; /* Highest sector ID read so far. */ ! 281: ! 282: /* ! 283: * Patchable parameters. ! 284: */ ! 285: ! 286: int fl_srt = 0xD; /* Floppy seek step rate, in unit -2 millisec */ ! 287: /* F=1ms, E=2ms, etc. */ ! 288: /* All drives HAVE to work at 5 msec/step, so */ ! 289: /* they HAVE to work at 6 msec/step! (The use of */ ! 290: /* 8 msec/step in the old PCs was just IBM being */ ! 291: /* excessively conservative. MS/PC-DOS, starting with */ ! 292: /* version 2.0, changes it to 6 msec/step. There */ ! 293: /* are, in fact, lots of drives that will step at */ ! 294: /* 4 msec/step, but there's no sense in pushing it.) */ ! 295: int fl_hlt = 25; /* Floppy head load time, in unit 4 millisec */ ! 296: int fl_hut = 0xF; /* Floppy head unload time, in unit 32 millisec */ ! 297: ! 298: CON fl386con = { ! 299: DFBLK | DFCHR, /* Flags */ ! 300: FL_MAJOR, /* Major index */ ! 301: flopen, /* Open */ ! 302: flclose, /* Close */ ! 303: flblock, /* Block */ ! 304: flread, /* Read */ ! 305: flwrite, /* Write */ ! 306: flioctl, /* Ioctl */ ! 307: nulldev, /* Powerfail */ ! 308: fltimeout, /* Timeout */ ! 309: flload, /* Load */ ! 310: flunload /* Unload */ ! 311: }; ! 312: ! 313: static int flOpenCount; /* Number of pending opens for this driver. */ ! 314: ! 315: /* ! 316: * ---------------------------------------------------------------------- ! 317: * Code. ! 318: */ ! 319: ! 320: /* ! 321: * The load routine asks the ! 322: * switches how many drives are present ! 323: * in the machine, and sets up the field ! 324: * in the floppy database. It also grabs ! 325: * the level 6 interrupt vector. ! 326: */ ! 327: static int ! 328: flload() ! 329: { ! 330: register int eflag; ! 331: register int s, t; ! 332: ! 333: /* set up interrupt handling routine */ ! 334: flIntr = flIntHandler; ! 335: fl_clrng_cd = 0; ! 336: ! 337: /* ! 338: * Read floppy equipment byte from CMOS ram ! 339: * drive 0 is in high nibble, drive 1 is in low nibble. ! 340: */ ! 341: eflag = read_cmos(0x10); ! 342: ! 343: /* ! 344: * Define AT drive information. ! 345: */ ! 346: fl.fl_type[0] = eflag >> 4; ! 347: fl.fl_type[1] = eflag & 15; ! 348: ! 349: /* ! 350: * Pretend no drives -- we haven't found any yet! ! 351: */ ! 352: fl.fl_ndsk = 0; ! 353: ! 354: /* ! 355: * Bang on all possible drives, setting startup vals ! 356: */ ! 357: for (s = 0; s < MAXDRVS; s++) { ! 358: drv_locked[s] = 0; /* not locked */ ! 359: fl.fl_dsk_chngd[s] = 1; /* disk has been changed */ ! 360: fl.fl_incal[s] = -1; /* not in calibration */ ! 361: t = fl.fl_type[s]; /* type of drive */ ! 362: if (t > MAXTYPE) /* --in case we get, like, */ ! 363: fl.fl_type[s] = t = MAXTYPE; /* a 2.88 meg drive. */ ! 364: fl.fl_rate[s] = frates[t].dflt_rate; /* default rate */ ! 365: fl.fl_fd[s] = fdata[frates[t].dflt_kind]; /* data params */ ! 366: if (t) fl.fl_ndsk = s + 1; /* Type 0 = no drive. */ ! 367: } ! 368: ! 369: fl.fl_rate_set = 0; ! 370: ! 371: if (fl_dsk_ch_prob) ! 372: jopen = 1; ! 373: ! 374: fl.fl_state = SIDLE; /* Initial state of IDLE */ ! 375: ! 376: fl.fl_mstatus = 0; /* No motors on */ ! 377: fl.fl_selected_unit = -1; /* No unit selected */ ! 378: } ! 379: ! 380: /* ! 381: * Release resources. ! 382: */ ! 383: static int ! 384: flunload() ! 385: { ! 386: /* ! 387: * Cancel timed function. ! 388: */ ! 389: timeout(&fltim, 0, NULL, NULL); ! 390: ! 391: /* ! 392: * Free the interrupt routine ! 393: */ ! 394: flIntr = NULL; ! 395: } ! 396: ! 397: /* ! 398: * The open routine screens out ! 399: * opens of illegal minor devices and ! 400: * performs the NEC specify command if ! 401: * this is the very first floppy disk ! 402: * open call. ! 403: * ! 404: * NOTICE: This routine needs to be fixed! There is a problem ! 405: * if first open is in progress and another first open is tried. ! 406: * hws - 93/05/18 ! 407: */ ! 408: static int ! 409: flopen(dev, mode) ! 410: dev_t dev; ! 411: int mode; ! 412: { ! 413: register int unit_number = funit(dev); ! 414: register int s; ! 415: ! 416: /* ! 417: * If first open, seize interrupt handler. ! 418: * Also bang on the FDC to get it warmed up - ! 419: * specify seek, load, and unload, and set rate. ! 420: */ ! 421: if (flOpenCount == 0) { ! 422: if (!setFlIntr(1)) { ! 423: devmsg(dev, "FDC busy."); ! 424: u.u_error = EBUSY; ! 425: goto worseFlopen; ! 426: } ! 427: fdcSpecify(fl_srt, fl_hut, fl_hlt); ! 428: fdcRate(fl.fl_rate_set); ! 429: } ! 430: ! 431: /* ! 432: * Validate existence and data rate (Gap length != 0). ! 433: */ ! 434: if ((unit_number >= fl.fl_ndsk) /* not over MAX drive */ ! 435: || (fl.fl_type[unit_number] == 0) /* existance */ ! 436: || (fdata[fkind(dev)].fd_GPL[flrate(dev)] == 0)) {/* gap len == 0 */ ! 437: u.u_error = ENXIO; ! 438: goto badFlopen; ! 439: } ! 440: ! 441: if (fl_dsk_ch_prob) ! 442: jopen = 1; ! 443: ! 444: /* ! 445: * May need to write - see if diskette is write proteced. ! 446: * We do this with a "Sense Drive Status" command. Since ! 447: * this requires the use of the FDC, we have to schedule it ! 448: * like data transfer I/O or FORMAT even though it doesn't ! 449: * use the DMA. ! 450: */ ! 451: if (fl.fl_opct[unit_number] == 0) { /* first open for this floppy */ ! 452: if (drv_locked[unit_number]) { /* Work areas avail? */ ! 453: u.u_error = EBUSY; /* No. */ ! 454: goto badFlopen; ! 455: } else { ! 456: drv_locked[unit_number] = 1; /* Grab work areas. */ ! 457: flbuf[unit_number].b_dev = dev; ! 458: flbuf[unit_number].b_req = BFLSTAT; ! 459: sw3[unit_number] = 0; ! 460: /* Get drive status. */ ! 461: /* Queue the request up */ ! 462: flQhang(&flbuf[unit_number]); ! 463: ! 464: for (;;) { ! 465: /* ! 466: * Enter the state machine and ! 467: * execute the commands pending. ! 468: */ ! 469: s = sphi(); ! 470: if (fl.fl_state == SIDLE) ! 471: flfsm(); ! 472: spl(s); ! 473: ! 474: /* ! 475: * if we have a result, exit the loop ! 476: */ ! 477: if (sw3[unit_number]) ! 478: break; ! 479: ! 480: /* ! 481: * Otherwise, if the drive is still ! 482: * busy, go to sleep. ! 483: */ ! 484: ! 485: if (fl.fl_state != SIDLE) ! 486: x_sleep(&fl.fl_state, ! 487: pridisk, slpriSigCatch, "flopen"); ! 488: ! 489: /* ! 490: * What woke us, a signal or the result? ! 491: * if signal, trap it here. Otherwise ! 492: * go back up to the top where we will ! 493: * bang on the drive again. ! 494: */ ! 495: ! 496: if (nondsig()) { /* signal? */ ! 497: u.u_error = EINTR; ! 498: drv_locked[unit_number] = 0; ! 499: goto badFlopen; ! 500: } ! 501: } ! 502: ! 503: if (flbuf[unit_number].b_resid != 0) { ! 504: u.u_error = EIO; /* Couldn't get drive */ ! 505: drv_locked[unit_number] = 0; ! 506: goto badFlopen; ! 507: } ! 508: ! 509: /* The payoff - set write enable status. */ ! 510: fl.fl_we[unit_number] = ! 511: ((sw3[unit_number] & ST3_WP)==0); ! 512: drv_locked[unit_number] = 0; /* Release work areas */ ! 513: } ! 514: ! 515: /* ! 516: * If the drive is low density (no change line) we should ! 517: * flag the need to verify the disk format and density. ! 518: * High density drives (which are also dual density) have ! 519: * change lines that we can check each time we want to read ! 520: * the drive. ! 521: */ ! 522: if (frates[fl.fl_type[unit_number]].fl_hi_rate == -1) { ! 523: fl.fl_incal[unit_number] = -1; ! 524: fl.fl_dsk_chngd[unit_number] = 1; ! 525: ! 526: if (fl_dsk_ch_prob) ! 527: jopen = 1; ! 528: } ! 529: } /* end of first open stuff */ ! 530: ! 531: /* If opening for write, volume must be write enabled. */ ! 532: if ((mode & IPW) && !fl.fl_we[unit_number]) { ! 533: printf("fd%d: <Write Protected>\n", fl.fl_unit); ! 534: u.u_error = EROFS; /* Diskette write */ ! 535: goto badFlopen; /* protected. */ ! 536: } ! 537: ! 538: fl.fl_opct[unit_number]++; ! 539: flOpenCount++; ! 540: return; ! 541: ! 542: badFlopen: ! 543: setFlIntr(0); ! 544: worseFlopen: ! 545: return; ! 546: } ! 547: ! 548: /* ! 549: * flclose() ! 550: */ ! 551: static ! 552: flclose(dev, mode) ! 553: dev_t dev; ! 554: int mode; ! 555: { ! 556: register int unit_number = funit(dev); ! 557: ! 558: /* ! 559: * Not sure it needed changing, but protect against negative ! 560: * close count - ljg ! 561: */ ! 562: if(--(fl.fl_opct[unit_number]) < 0) ! 563: fl.fl_opct[unit_number] = 0; ! 564: if (--flOpenCount == 0) ! 565: setFlIntr(0); ! 566: } ! 567: ! 568: /* ! 569: * The read routine just calls ! 570: * off to the common raw I/O processing ! 571: * code, using a static buffer header in ! 572: * the driver. ! 573: */ ! 574: static int ! 575: flread(dev, iop) ! 576: dev_t dev; ! 577: IO *iop; ! 578: { ! 579: dmareq(&flbuf[funit(dev)], iop, dev, BREAD); ! 580: } ! 581: ! 582: /* ! 583: * The write routine is just like the ! 584: * read routine, except that the function code ! 585: * is write instead of read. ! 586: */ ! 587: static int ! 588: flwrite(dev, iop) ! 589: dev_t dev; ! 590: IO *iop; ! 591: { ! 592: dmareq(&flbuf[funit(dev)], iop, dev, BWRITE); ! 593: } ! 594: ! 595: /* ! 596: * The ioctl routine simply queues a format request ! 597: * using the flbuf for the specified drive. ! 598: * The only valid command is to format a track. ! 599: * The parameter block contains the header records supplied to the controller. ! 600: */ ! 601: ! 602: static int ! 603: flioctl(dev, com, par) ! 604: dev_t dev; ! 605: int com; ! 606: char *par; ! 607: { ! 608: register unsigned s; ! 609: register struct fdata *fdp; ! 610: unsigned hd, cyl; ! 611: IO io; ! 612: ! 613: if (com != FDFORMAT) { ! 614: u.u_error = EINVAL; ! 615: return; ! 616: } ! 617: ! 618: /* ! 619: * We do not allow formatting of special devices. ! 620: * Possible future mod. ! 621: */ ! 622: ! 623: if (fisspecial (dev)) { ! 624: u.u_error = EINVAL; ! 625: return; ! 626: } ! 627: ! 628: ! 629: fdp = & fdata [fkind (dev)]; /* Locate formatting */ ! 630: cyl = getubd (par); /* parameters. */ ! 631: hd = getubd (par+1); ! 632: ! 633: if (hd > 1 || cyl >= fdp->fd_trks) { ! 634: u.u_error = EINVAL; ! 635: return; ! 636: } ! 637: ! 638: /* ! 639: * The following may need some explanation. ! 640: * dmareq will: ! 641: * claim the buffer, ! 642: * bounds check the parameter buffer, ! 643: * lock the parameter buffer in memory, ! 644: * convert io_seek to b_bno, ! 645: * dispatch the request, ! 646: * wait for completion, ! 647: * and unlock the parameter buffer. ! 648: * The b_bno is reconverted to hd, cyl in flfsm. ! 649: */ ! 650: ! 651: /* ! 652: * Convert to seek number based on whether or not we are running ! 653: * sbys or hbyh. ! 654: * Now we are always running hbyh, so this gets commented out ! 655: * and should eventually be removed. -louis 7/93 ! 656: */ ! 657: ! 658: /* s = fhbyh(dev) ? (cyl * fdp->fd_nhds + hd) : (hd * fdp->fd_trks + cyl); */ ! 659: s = (cyl * fdp->fd_nhds + hd); ! 660: s *= fdp->fd_nspt; ! 661: ! 662: /* ! 663: * Build the device I/O request. ! 664: */ ! 665: ! 666: io.io_seg = IOUSR; ! 667: io.io_seek = (long) s * BSIZE; ! 668: io.io.vbase = par; ! 669: io.io_ioc = fdp->fd_nspt * 4; ! 670: ! 671: /* ! 672: * Hand off to the dmareq routine (i.e., indirectly call ! 673: * flblock() letting dmareq() do all the dirty work). ! 674: */ ! 675: dmareq (& flbuf [funit (dev)], & io, dev, BFLFMT); ! 676: return 0; ! 677: } ! 678: ! 679: /* ! 680: * Start up block I/O on a ! 681: * buffer. Check that the block number ! 682: * is not out of range, given the style of ! 683: * the disk. Put the buffer header into the ! 684: * device queue. Start up the disk if the ! 685: * device is idle. ! 686: */ ! 687: static int ! 688: flblock(bp) ! 689: register BUF *bp; ! 690: { ! 691: register int s; ! 692: register unsigned bno; ! 693: ! 694: /* ! 695: * Compute the ending block of the transfer. ! 696: */ ! 697: bno = bp->b_bno + (bp->b_count / BSIZE) - 1; ! 698: ! 699: ! 700: { /*DEBUG*/ ! 701: int first = bp->b_bno, last = bno; ! 702: int fdatasz = fdata[fkind(bp->b_dev)].fd_size; ! 703: int fl_fdsz = fl.fl_fd[funit(bp->b_dev)].fd_size; ! 704: /*DEBUG*/ ! 705: ! 706: /* ! 707: * If we're formatting, make sure that the starting block ! 708: * number is within range for the device...the range is the ! 709: * entire device range. ! 710: */ ! 711: if ((bp->b_req == BFLFMT) ! 712: && ((unsigned)bp->b_bno >= fdata[fkind(bp->b_dev)].fd_size)) { ! 713: bp->b_flag |= BFERR; ! 714: bdone(bp); ! 715: return; ! 716: } ! 717: ! 718: ! 719: /* ! 720: * Here, we are checking the current setttings for each device ! 721: * rather than the defaults for the type of device. This is for ! 722: * a read/write rather than a format. ! 723: * ! 724: * Quickly hacked to check on special devices that skip cylinder 0 ! 725: * since they are missing a cylinder's worth of sectors. ! 726: */ ! 727: if (bp->b_req != BFLFMT) { ! 728: /* ! 729: * Check starting block to see if in range ! 730: */ ! 731: if ((unsigned)bp->b_bno + (fskip_cyl_0(bp->b_dev) ? \ ! 732: fl.fl_fd[funit(bp->b_dev)].fd_nspt*2 : 0) >= \ ! 733: fl.fl_fd[funit(bp->b_dev)].fd_size) { ! 734: bp->b_flag |= BFERR; ! 735: bdone(bp); ! 736: return; ! 737: } ! 738: ! 739: /* ! 740: * Here we check the ending number to see if that ! 741: * is within range. ! 742: */ ! 743: if (bno + (fskip_cyl_0(bp->b_dev) ? \ ! 744: fl.fl_fd[funit(bp->b_dev)].fd_nspt*2 : 0) >= \ ! 745: fl.fl_fd[funit(bp->b_dev)].fd_size) { ! 746: if (bp->b_flag & BFRAW) { ! 747: bp->b_flag |= BFERR; ! 748: } ! 749: bp->b_resid = bp->b_count; ! 750: bdone(bp); /* return w/ b_resid != 0 */ ! 751: return; ! 752: } ! 753: ! 754: /* ! 755: * Finally, make sure the byte count is a multiple ! 756: * of 512 (the number of bytes per physical sector). ! 757: */ ! 758: if ((bp->b_count & 0x1FF) != 0) { ! 759: bp->b_flag |= BFERR; ! 760: bdone(bp); ! 761: return; ! 762: } ! 763: } ! 764: } /*DEBUG*/ ! 765: ! 766: flQhang(bp); /* Put the block in the queue. */ ! 767: ! 768: s = sphi(); ! 769: if (fl.fl_state == SIDLE) /* --if necessary, to */ ! 770: flfsm(); /* get things moving. */ ! 771: spl(s); ! 772: } ! 773: ! 774: /******************************************************************/ ! 775: ! 776: /* Lower-level functions needed by CON entry points. */ ! 777: ! 778: /* ! 779: * This routine hangs a BUF in the processing queue ! 780: */ ! 781: static void ! 782: flQhang(bp) ! 783: register BUF *bp; ! 784: { ! 785: register int s = sphi(); /* No interrupts during chaining, please */ ! 786: ! 787: bp->b_actf = NULL; ! 788: ! 789: if (fl.fl_actf == NULL) ! 790: fl.fl_actf = bp; ! 791: else ! 792: fl.fl_actl->b_actf = bp; ! 793: ! 794: fl.fl_actl = bp; ! 795: ! 796: spl(s); ! 797: } ! 798: ! 799: /* ! 800: * Remove all pending requests for a device from the queue ! 801: * (used after errors). ! 802: */ ! 803: static void ! 804: clrQ(dev) ! 805: register int dev; ! 806: { ! 807: register BUF *bp, *bp2; ! 808: int s; ! 809: ! 810: s = sphi(); ! 811: ! 812: while ((bp = fl.fl_actf) && (bp->b_dev == dev)) { ! 813: bp->b_flag |= BFERR; /* Strip BUFs from front */ ! 814: fl.fl_actf = bp->b_actf; /* of queue. */ ! 815: bdone(bp); ! 816: } ! 817: while (bp) { ! 818: fl.fl_actl = bp; ! 819: if ((bp2 = bp->b_actf) && (bp2->b_dev == dev)) { ! 820: bp2->b_flag |= BFERR; /* Strip BUFs from rest */ ! 821: bp->b_actf = bp2->b_actf; /* rest of queue. */ ! 822: bdone(bp2); ! 823: } else ! 824: bp = bp2; ! 825: } ! 826: fl.fl_state = SIDLE; ! 827: wakeup(&fl.fl_state); ! 828: spl(s); ! 829: } ! 830: ! 831: /* ! 832: * This finite state machine is ! 833: * responsible for all sequencing on the disk. ! 834: * It builds the commands, does the seeks, spins up ! 835: * the drive motor for 1 second on the first call, ! 836: * and so on. ! 837: * Note that the format command is rather obscurely shoehorned into this. ! 838: */ ! 839: void ! 840: flfsm() ! 841: { ! 842: register BUF *bp; ! 843: register int flcmd; ! 844: register int i; ! 845: int dods; /* for PS/1, do disk swap */ ! 846: ! 847: again: ! 848: /* ! 849: * This gets the head of the floppy request queue. ! 850: */ ! 851: bp = fl.fl_actf; ! 852: ! 853: switch (fl.fl_state) { ! 854: ! 855: case SIDLE: ! 856: T_HAL(0x40000, printf("SIDLE ")); ! 857: /* ! 858: * Set the timer for floppy access. ! 859: */ ! 860: setFlTimer(1); ! 861: ! 862: /* ! 863: * One way out completely is if there are no more ! 864: * I/O requests and we are in an IDLE state. ! 865: */ ! 866: if (bp == NULL) { ! 867: break; ! 868: } ! 869: ! 870: fl.fl_unit = funit(bp->b_dev); ! 871: fl.fl_mask = 0x10 << fl.fl_unit; ! 872: ! 873: #if 0 ! 874: printf("drv%d: cmd=%d (%s), position=%d, count=%d\n", ! 875: fl.fl_unit, ! 876: bp->b_req, ! 877: (bp->b_req == BREAD) ? "BREAD" ! 878: : (bp->b_req == BWRITE) ? "BWRITE" ! 879: : (bp->b_req == BFLSTAT) ? "BFLSTAT" ! 880: : (bp->b_req == BFLFMT) ? "BFLFMT" : "?????", ! 881: bp->b_bno, ! 882: bp->b_count); ! 883: #endif ! 884: /* ! 885: * We do an entire check for drive status here ! 886: */ ! 887: if (bp->b_req == BFLSTAT) { ! 888: /* ! 889: * Clear status buffer and get new status. ! 890: */ ! 891: fl.fl_drvstat[0] = 0; ! 892: flDrvStatus(); ! 893: ! 894: /* ! 895: * Why |3 ??!?!? -louis ! 896: */ ! 897: sw3[fl.fl_unit] = fl.fl_drvstat[0] | 3; ! 898: bp->b_resid = (fl.fl_ndrvstat == 1) ? 0 : 1; ! 899: ! 900: /* ! 901: * set up to service next request. ! 902: * and service it immediately by goto again. ! 903: */ ! 904: fl.fl_actf = bp->b_actf; ! 905: fl.fl_state = SIDLE; ! 906: goto again; ! 907: } ! 908: ! 909: /* ! 910: * Only service hbyh now. Original rval computation ! 911: * in comment. Should remove eventually. - ljg 7/93 ! 912: */ ! 913: fl.fl_hbyh = 1; /* fhbyh(bp->b_dev); */ ! 914: ! 915: /* ! 916: * Get physical address and starting postition. ! 917: * Also set timeout value to zero. ! 918: */ ! 919: fl.fl_addr = bp->b_paddr; ! 920: fl.fl_secn = bp->b_bno; ! 921: fl.fl_time[fl.fl_unit] = 0; ! 922: ! 923: /* ! 924: * Make sure we read at least one sector. ! 925: * Even if the request is for say 20 bytes. ! 926: */ ! 927: if ((fl.fl_nsec = bp->b_count>>9) == 0) ! 928: fl.fl_nsec = 1; ! 929: ! 930: fl.fl_nerr = 0; ! 931: ! 932: /* ! 933: * Motor is turned off - turn it on, wait 1 second ! 934: * (for write operations only) ! 935: * flDrvSelect() is who selects the drive and turns ! 936: * the motor on. ! 937: */ ! 938: if (((fl.fl_mstatus & fl.fl_mask) == 0) ! 939: || (fl.fl_unit != fl.fl_selected_unit)) { ! 940: flDrvSelect(); ! 941: if ((bp->b_req == BWRITE) ! 942: || (bp->b_req == BFLFMT)) { ! 943: timeout(&fltim, HZ, fldelay, SSEEK); ! 944: fl.fl_state = SDELAY; ! 945: break; ! 946: } ! 947: } ! 948: ! 949: /* no break */ ! 950: /* The "fsm" is fairly vile in gotos, fallthroughs, ! 951: * and other hazy notions of jumping from state to ! 952: * state without following a true transition edge. ! 953: * This is one example. ! 954: */ ! 955: ! 956: case SSEEK: ! 957: T_HAL(0x40000, printf("SSEEK ")); ! 958: ! 959: /* In a fallthrough, this line would be a waste. */ ! 960: flDrvSelect(); /* Keep drive turned on */ ! 961: ! 962: /* ! 963: * Test dual-density drive's disk changed line. We must ! 964: * test now before we (possibly) recalibrate the drive ! 965: * which would lose us the disk changed indication. ! 966: */ ! 967: ! 968: if ((frates[fl.fl_type[fl.fl_unit]].fl_hi_rate != -1) ! 969: && (inb(FDCCHGL) & DSKCHGD) ! 970: && (fl_clrng_cd == 0)) { ! 971: /* See note at def of fl_dsk_ch_prob above */ ! 972: ! 973: /* ! 974: * Hmm. I would have done this: ! 975: * if((FL_DSK_PROB && jopen) || !(FL_DSK_PROB)) ! 976: * instead of multiple if's, but that's me. ! 977: * -louis ! 978: */ ! 979: if (fl_dsk_ch_prob) { ! 980: if (jopen) { ! 981: jopen--; ! 982: fl.fl_dsk_chngd[fl.fl_unit] = 1; ! 983: fl.fl_incal[fl.fl_unit] = -1; ! 984: } ! 985: } else { ! 986: fl.fl_dsk_chngd[fl.fl_unit] = 1; ! 987: fl.fl_incal[fl.fl_unit] = -1; ! 988: } ! 989: } ! 990: ! 991: fl_clrng_cd = 0; ! 992: ! 993: /* ! 994: * If we have a format command on cylinder zero, head ! 995: * zero, we must recalibrate the drive first, and set ! 996: * up the transfer speed and FDC stuff. We ignore ! 997: * a disk changed condition since the current format ! 998: * (it may, remember, be unformatted!) is of no ! 999: * consequence. ! 1000: */ ! 1001: ! 1002: /* NOTE: ! 1003: * Since formats to special devices are not currently ! 1004: * allowed, this code should never be reached when ! 1005: * the device is special. Therefore, if formats ! 1006: * to special devices are allowed later, this code ! 1007: * may need to be updated. ! 1008: */ ! 1009: if (bp->b_req == BFLFMT) { ! 1010: /* ! 1011: * By making disk changed 0 we can avoid ! 1012: * figuring out the type of disk since we ! 1013: * don't care -- we're formatting (it may ! 1014: * be a 1.2M that we're formatting to 360K ! 1015: * anyhow. ! 1016: */ ! 1017: fl.fl_dsk_chngd[fl.fl_unit] = 0; ! 1018: ! 1019: /* ! 1020: * Here we just set up params for the ! 1021: * current drive in normal tables so ! 1022: * we don't need to index the current unit ! 1023: * any more. ! 1024: */ ! 1025: fl.fl_fd[fl.fl_unit] = fdata[fkind(bp->b_dev)]; ! 1026: fl.fl_rate[fl.fl_unit] = ! 1027: fl.fl_rate_set = flrate(bp->b_dev); ! 1028: ! 1029: /* ! 1030: * If less than 45 tracks and we're not a 360K ! 1031: * drive, then we need to double step ! 1032: * the drive. ! 1033: */ ! 1034: if ((fl.fl_fd[fl.fl_unit].fd_trks < 45) ! 1035: && (fl.fl_type[fl.fl_unit] != 1)) ! 1036: fl.fl_2step[fl.fl_unit] = 1; ! 1037: ! 1038: fdcRate(fl.fl_rate_set); ! 1039: if (fl.fl_secn == 0) ! 1040: fl.fl_incal[fl.fl_unit] = -1; ! 1041: } ! 1042: /* ! 1043: * Drive is not calibrated - seek to track 0. ! 1044: */ ! 1045: if (fl.fl_incal[fl.fl_unit] == -1) { ! 1046: fdcRecal(fl.fl_unit); ! 1047: fl.fl_state = SRECAL1; ! 1048: break; ! 1049: } else goto Recalibrated; ! 1050: ! 1051: case SRECAL1: ! 1052: T_HAL(0x40000, printf("SRECAL1 ")); ! 1053: /* ! 1054: * If the recalibrate had to step more than 77 cylinders ! 1055: * it will fail. We must check for this condition and ! 1056: * try once more. With some controllers we will also get ! 1057: * an error if the head STARTS over cylinder 0. In either ! 1058: * event we will force a seek to track 2, then recalibrate ! 1059: * again. If this fails, we can't recalibrate the drive. ! 1060: */ ! 1061: if ((fdc.fdc_nintstat != 2) ! 1062: || ((fdc.fdc_intstat[0] & (ST0_IC | ST0_SE)) != ST0_SE)) { ! 1063: ! 1064: /* Seek to current drive #, head 0, cylinder 2. */ ! 1065: fdcSeek(fl.fl_unit, 0, 2); ! 1066: ! 1067: fl.fl_state = SRECAL2; ! 1068: break; ! 1069: } else goto RecalibrateOK; ! 1070: case SRECAL2: ! 1071: T_HAL(0x40000, printf("SRECAL2 ")); ! 1072: fdcRecal(fl.fl_unit); ! 1073: fl.fl_state = SRECAL3; ! 1074: break; ! 1075: case SRECAL3: ! 1076: T_HAL(0x40000, printf("SRECAL3 ")); ! 1077: if ((fdc.fdc_nintstat != 2) ! 1078: || ((fdc.fdc_intstat[0] & (ST0_IC | ST0_SE)) != ST0_SE)) { ! 1079: RecalFailed: ! 1080: printf("fd%d: <Can't Recalibrate>\n", fl.fl_unit); ! 1081: clrQ(bp->b_dev); ! 1082: goto again; ! 1083: } ! 1084: RecalibrateOK: ! 1085: /* We now get off of cyl 0 */ ! 1086: /* to try to clear the disk */ ! 1087: /* changed line, which acts */ ! 1088: /* differently on different */ ! 1089: /* controllers. <sigh> We */ ! 1090: /* use cyl 2 since all for- */ ! 1091: /* matted disks will have a */ ! 1092: /* track here. */ ! 1093: ! 1094: /* Seek to current drive #, head 0, cylinder 2. */ ! 1095: fdcSeek(fl.fl_unit, 0, 2); ! 1096: ! 1097: fl.fl_state = SGOTO2; ! 1098: break; ! 1099: ! 1100: case SGOTO2: ! 1101: T_HAL(0x40000, printf("SGOTO2 ")); ! 1102: if ((fdc.fdc_nintstat != 2) ! 1103: || ((fdc.fdc_intstat[0] & (ST0_IC | ST0_SE)) != ST0_SE)) ! 1104: goto RecalFailed; ! 1105: ! 1106: fl.fl_incal[fl.fl_unit] = 2; /* Heads now on cylinder 2. */ ! 1107: ! 1108: Recalibrated: ! 1109: /* ! 1110: * Now, if we don't have to check the interleave factor, ! 1111: * we can continue with the seek! ! 1112: */ ! 1113: if (fl.fl_dsk_chngd[fl.fl_unit] == 0) goto RateKnown; ! 1114: ! 1115: /* ! 1116: * <sigh>. Okay, first we'll try the requested density. ! 1117: */ ! 1118: ! 1119: /* First we'll make sure */ ! 1120: /* we're sitting on cyl 2. */ ! 1121: if (fl.fl_incal[fl.fl_unit] != 2) goto RecalibrateOK; ! 1122: ! 1123: /* ! 1124: * We start by trying the requested density: ! 1125: */ ! 1126: ! 1127: /* Get requested rate.*/ ! 1128: i = fl.fl_rate[fl.fl_unit] = flrate(bp->b_dev); ! 1129: /* This next mess gets*/ ! 1130: /* the disk parameters*/ ! 1131: /* and the alternate */ ! 1132: /* values. */ ! 1133: /* ! 1134: * Auto_parm defaults to active now, and is used ! 1135: * for the appropriate minor devices. It can be ! 1136: * patched to 0 if it causes problems with someone's ! 1137: * floppy, but then the iBCS2 devices that autosense ! 1138: * won't autosense anymore :-( -louis ! 1139: */ ! 1140: ! 1141: if (i == frates[fl.fl_type[fl.fl_unit]].fl_hi_rate){ ! 1142: ! 1143: fl.fl_fd[fl.fl_unit] = ! 1144: fdata[frates[fl.fl_type[fl.fl_unit]].fl_hi_kind]; ! 1145: if (fl_auto_parm && fautosense(bp->b_dev)) { ! 1146: fl_alt_kind = ! 1147: frates[fl.fl_type[fl.fl_unit]].fl_lo_kind; ! 1148: fl_alt_rate = ! 1149: frates[fl.fl_type[fl.fl_unit]].fl_lo_rate; ! 1150: } else { ! 1151: fl_alt_kind = ! 1152: frates[fl.fl_type[fl.fl_unit]].fl_hi_kind; ! 1153: fl_alt_rate = ! 1154: frates[fl.fl_type[fl.fl_unit]].fl_hi_rate; ! 1155: } ! 1156: } else { ! 1157: fl.fl_fd[fl.fl_unit] = ! 1158: fdata[frates[fl.fl_type[fl.fl_unit]].fl_lo_kind]; ! 1159: if (fl_auto_parm && fautosense(bp->b_dev)) { ! 1160: fl_alt_kind = ! 1161: frates[fl.fl_type[fl.fl_unit]].fl_hi_kind; ! 1162: fl_alt_rate = ! 1163: frates[fl.fl_type[fl.fl_unit]].fl_hi_rate; ! 1164: } else { ! 1165: fl_alt_kind = ! 1166: frates[fl.fl_type[fl.fl_unit]].fl_lo_kind; ! 1167: fl_alt_rate = ! 1168: frates[fl.fl_type[fl.fl_unit]].fl_lo_rate; ! 1169: } ! 1170: } ! 1171: ! 1172: fl.fl_state = SRDID; /* Set up to read sector IDs. */ ! 1173: fl_get_intlv = 1; ! 1174: fl_intlv_ct = ! 1175: fl_lk4_id = ! 1176: fl_1st_ID = ! 1177: fl_hi_ID = 0; ! 1178: ! 1179: /* ! 1180: * Now we try the rate to see if we can read sector IDs ! 1181: */ ! 1182: TryRate: ! 1183: if (fl.fl_rate_set != i) { ! 1184: fl.fl_rate_set = i; ! 1185: fdcRate(fl.fl_rate_set); ! 1186: } ! 1187: GetNextID: ! 1188: /* Always read side 0. */ ! 1189: fdcReadID(fl.fl_unit, 0); ! 1190: ! 1191: break; /* Wait for ID to arrive. */ ! 1192: ! 1193: case SRDID: ! 1194: T_HAL(0x40000, printf("SRDID ")); ! 1195: ! 1196: if ((fdc.fdc_ncmdstat < 7) /* Did we get an ID? */ ! 1197: || ((fdc.fdc_cmdstat[0] & ST0_IC) != ST0_NT) ) { ! 1198: if (fl_alt_rate == -1) { /* No, is there an alternate?*/ ! 1199: fdcStatus(); /* No, we can't go on. */ ! 1200: clrQ(bp->b_dev); ! 1201: goto again; ! 1202: } else { ! 1203: fl.fl_fd[fl.fl_unit] = fdata[fl_alt_kind]; ! 1204: i = fl.fl_rate[fl.fl_unit] = fl_alt_rate; ! 1205: fl_alt_rate = -1; /* Flag tried alternate. */ ! 1206: goto TryRate; /* Try alternate density. */ ! 1207: } ! 1208: } ! 1209: ! 1210: /* ! 1211: * Test interleave ! 1212: */ ! 1213: ! 1214: if (fl_get_intlv) /* Looking for interleave? */ ! 1215: if (fl_lk4_id) { /* Yes; started yet? */ ! 1216: if (fl_lk4_id == fdc.fdc_cmdstat[5]) /* Yes. */ ! 1217: fl_get_intlv = 0; /* We have a hit.*/ ! 1218: else /* No hit yet, */ ! 1219: fl_intlv_ct++; /* count sector. */ ! 1220: } else if (fdc.fdc_cmdstat[5] < 5) {/* Can we start yet?*/ ! 1221: fl_intlv_ct = 1; /* Yes; count, */ ! 1222: fl_lk4_id = fdc.fdc_cmdstat[5] + 1;/* set ID */ ! 1223: } /* to find.*/ ! 1224: ! 1225: /* ! 1226: * Look for highest ID on track ! 1227: */ ! 1228: ! 1229: if (fdc.fdc_cmdstat[5] != fl_1st_ID) { ! 1230: if (fl_1st_ID == 0) ! 1231: fl_1st_ID = fdc.fdc_cmdstat[5]; ! 1232: if (fdc.fdc_cmdstat[5] > fl_hi_ID) ! 1233: fl_hi_ID = fdc.fdc_cmdstat[5]; ! 1234: goto GetNextID; ! 1235: } ! 1236: ! 1237: /* ! 1238: * Be sure we have the interleave ! 1239: */ ! 1240: ! 1241: if (fl_get_intlv) goto GetNextID; ! 1242: ! 1243: /* ! 1244: * So now we know the density and sectors/track ! 1245: */ ! 1246: ! 1247: fl.fl_dsk_chngd[fl.fl_unit] = 0; ! 1248: fl.fl_fd[fl.fl_unit].fd_nspt = fl_hi_ID; ! 1249: ! 1250: /* ! 1251: * There is a problem with the approach used here - ! 1252: * it assumes that once scan of a track starts, all ! 1253: * sectors appear in physical order without any misses. ! 1254: * Unfortunately, this is not always the case, especially ! 1255: * with 1.44 M 3-1/2" drives. ! 1256: * ! 1257: * A workaround which fixes incorrect nspt reading appears ! 1258: * below. ! 1259: */ ! 1260: if (fl.fl_fd[fl.fl_unit].fd_nspt > 15 ! 1261: && fl.fl_fd[fl.fl_unit].fd_nspt < 18) ! 1262: fl.fl_fd[fl.fl_unit].fd_nspt = 18; ! 1263: ! 1264: /* ! 1265: * We're (supposedly) sitting on track 2. We'll ! 1266: * look at the last sector ID we've read. If it's 1, ! 1267: * we need to do double-stepping. ! 1268: */ ! 1269: ! 1270: if (fl.fl_2step[fl.fl_unit] = (fdc.fdc_cmdstat[3] == 1)) { ! 1271: fl.fl_fd[fl.fl_unit].fd_trks = FL_CYL_2STEP; ! 1272: fl.fl_incal[fl.fl_unit] = 1; ! 1273: } else /* Most 1.2M drives */ ! 1274: fl.fl_fd[fl.fl_unit].fd_trks = /* have 83 cyls! */ ! 1275: (fl.fl_type[fl.fl_unit] == 2) ! 1276: ? FL_CYL_HDHI : FL_CYL_HDLO; ! 1277: ! 1278: /* ! 1279: * We next test for one or two sides: ! 1280: */ ! 1281: ! 1282: if (fl.fl_rate[fl.fl_unit] == 0) { /* If diskette is */ ! 1283: fl.fl_fd[fl.fl_unit].fd_nhds = 2; /* high-density it*/ ! 1284: goto DiskEstablished; /* will have two */ ! 1285: } /* sides. */ ! 1286: ! 1287: /* ! 1288: * If the diskette is requested by caller as low density ! 1289: * we use the specified number of sides------ ! 1290: */ ! 1291: ! 1292: if (fdata[fkind(bp->b_dev)].fd_nspt < 12) { ! 1293: fl.fl_fd[fl.fl_unit].fd_nhds = ! 1294: fdata[fkind(bp->b_dev)].fd_nhds; ! 1295: goto DiskEstablished; ! 1296: } ! 1297: ! 1298: /* ! 1299: * --otherwise we check to see: ! 1300: * Try to read ANY sector ID from side two. ! 1301: */ ! 1302: fdcReadID(fl.fl_unit, 1); ! 1303: fl.fl_state = SSIDTST; ! 1304: break; ! 1305: ! 1306: case SSIDTST: /* If we succeeded, we have */ ! 1307: T_HAL(0x40000, printf("SSIDTST ")); ! 1308: /* 2 sides, else we have 1. */ ! 1309: fl.fl_fd[fl.fl_unit].fd_nhds = ((fdc.fdc_ncmdstat < 7) ! 1310: || ((fdc.fdc_cmdstat[0] & ST0_IC) != ST0_NT) ) ? 1 : 2; ! 1311: ! 1312: /* ! 1313: * So now we now know all about the diskette! ! 1314: */ ! 1315: DiskEstablished: ! 1316: fl.fl_fd[fl.fl_unit].fd_size = fl.fl_fd[fl.fl_unit].fd_nhds ! 1317: * fl.fl_fd[fl.fl_unit].fd_trks ! 1318: * fl.fl_fd[fl.fl_unit].fd_nspt; ! 1319: ! 1320: if (fl_disp) { ! 1321: printf("fl%d: rate=%d, sctrs/trk=%d, hds=%d, cyls=%d," ! 1322: " size=%d, intlv=%d, stp=%d\n", ! 1323: fl.fl_unit, ! 1324: fl.fl_rate[fl.fl_unit], ! 1325: fl.fl_fd[fl.fl_unit].fd_nspt, ! 1326: fl.fl_fd[fl.fl_unit].fd_nhds, ! 1327: fl.fl_fd[fl.fl_unit].fd_trks, ! 1328: fl.fl_fd[fl.fl_unit].fd_size, ! 1329: fl_intlv_ct, ! 1330: fl.fl_2step[fl.fl_unit]+1); ! 1331: } ! 1332: ! 1333: RateKnown: ! 1334: /* ! 1335: * Set data rate if changed. ! 1336: */ ! 1337: if (fl.fl_rate_set != (i = fl.fl_rate[fl.fl_unit])) { ! 1338: fl.fl_rate_set = i; ! 1339: fdcRate(fl.fl_rate_set); ! 1340: } ! 1341: ! 1342: /* ! 1343: * Next we must convert the ordinal block number to ! 1344: * cylinder/head/sector form. ! 1345: */ ! 1346: fl.fl_fsec = (fl.fl_secn % fl.fl_fd[fl.fl_unit].fd_nspt) + 1; ! 1347: ! 1348: #if ALLOW_SEEK_SURFACE_BY_SURFACE ! 1349: /* ! 1350: * Minor numbers used for surface by surface seek have ! 1351: * been reassigned. ! 1352: * Will keep the old code around for awile, though. ! 1353: */ ! 1354: ! 1355: if (fl.fl_hbyh) { ! 1356: ! 1357: /* ! 1358: * Seek cylinder by cylinder (XENIX/DOS compatible). ! 1359: */ ! 1360: fl.fl_head = fl.fl_secn / fl.fl_fd[fl.fl_unit].fd_nspt; ! 1361: fl.fl_fcyl = fl.fl_head / fl.fl_fd[fl.fl_unit].fd_nhds; ! 1362: fl.fl_head = fl.fl_head % fl.fl_fd[fl.fl_unit].fd_nhds; ! 1363: ! 1364: } else { ! 1365: ! 1366: /* ! 1367: * Seek surface by surface. ! 1368: */ ! 1369: fl.fl_fcyl = fl.fl_secn / fl.fl_fd[fl.fl_unit].fd_nspt; ! 1370: fl.fl_head = fl.fl_fcyl / fl.fl_fd[fl.fl_unit].fd_trks; ! 1371: fl.fl_fcyl = fl.fl_fcyl % fl.fl_fd[fl.fl_unit].fd_trks; ! 1372: ! 1373: } ! 1374: #else ! 1375: /* ! 1376: * This should always be done from now on. Original ! 1377: * code conditioned out. Should eventually be ! 1378: * removed. louis 7/93 ! 1379: * ! 1380: * Also, if it is a special device that skips track 0, ! 1381: * we just bang the cylinder number up by 1. ! 1382: */ ! 1383: ! 1384: fl.fl_head = fl.fl_secn / fl.fl_fd[fl.fl_unit].fd_nspt; ! 1385: fl.fl_fcyl = fl.fl_head / fl.fl_fd[fl.fl_unit].fd_nhds; ! 1386: if (fskip_cyl_0(bp->b_dev)) ! 1387: fl.fl_fcyl++; ! 1388: fl.fl_head = fl.fl_head % fl.fl_fd[fl.fl_unit].fd_nhds; ! 1389: #endif ! 1390: ! 1391: /* Don't seek unless we have to. */ ! 1392: if (fl.fl_fcyl == fl.fl_incal[fl.fl_unit]) ! 1393: goto Sought; /* Past tense of seek. */ ! 1394: ! 1395: fl.fl_incal[fl.fl_unit] = fl.fl_fcyl; /* Save new cylinder. */ ! 1396: ! 1397: if ((fl.fl_fd[fl.fl_unit].fd_trks < 45) ! 1398: && (fl.fl_type[fl.fl_unit] != 1)) { ! 1399: ! 1400: /* If disk is around 40 tracks*/ ! 1401: /* and drive is not 40 track- */ ! 1402: /* -use double step. */ ! 1403: fdcSeek(fl.fl_unit, fl.fl_head, (fl.fl_fcyl << 1)); ! 1404: ! 1405: } else { ! 1406: /* Single step. */ ! 1407: fdcSeek(fl.fl_unit, fl.fl_head, fl.fl_fcyl); ! 1408: } ! 1409: ! 1410: fl.fl_state = SHDLY; ! 1411: break; ! 1412: ! 1413: case SHDLY: ! 1414: T_HAL(0x40000, printf("SHDLY ")); ! 1415: /* ! 1416: * Delay for minimum 15 milliseconds after seek before w/fmt. ! 1417: * 2 clock ticks would give 10-20 millisecond (100 Hz clock). ! 1418: * 3 clock ticks gives 20-30 millisecond (100 Hz clock). ! 1419: */ ! 1420: if (bp->b_req != BREAD) { ! 1421: timeout(&fltim, 3, fldelay, SRDWR); ! 1422: fl.fl_state = SDELAY; ! 1423: break; ! 1424: } ! 1425: /* no break */ ! 1426: ! 1427: case SRDWR: ! 1428: T_HAL(0x40000, printf("SRDWR ")); ! 1429: Sought: ! 1430: /* ! 1431: * Disable watchdog timer while waiting to lock DMA controller. ! 1432: */ ! 1433: fl.fl_time[fl.fl_unit] = -1; ! 1434: ! 1435: /* ! 1436: * Next state will be DMA locked state. ! 1437: */ ! 1438: fl.fl_state = SLOCK; ! 1439: ! 1440: /* ! 1441: * If DMA controller locked by someone else, exit for now. ! 1442: */ ! 1443: if (dmalock(&fldmalck, flfsm, 0) != 0) ! 1444: return; ! 1445: ! 1446: case SLOCK: ! 1447: T_HAL(0x40000, printf("SLOCK ")); ! 1448: /* ! 1449: * Reset watchdog timer to restart timeout sequence. ! 1450: */ ! 1451: ! 1452: fl.fl_time[fl.fl_unit] = 0; ! 1453: ! 1454: flcmd = FDC_CMD_RDAT; ! 1455: fl.fl_wflag = 0; ! 1456: ! 1457: if (fl_clrng_cd == 0) ! 1458: if (bp->b_req == BWRITE) { ! 1459: fl.fl_wflag = 1; ! 1460: flcmd = FDC_CMD_WDAT; ! 1461: } ! 1462: ! 1463: else if (bp->b_req == BFLFMT) { ! 1464: fl.fl_wflag = 1; ! 1465: flcmd = FDC_CMD_FMT; ! 1466: ! 1467: if(!dmaon(DMA_CH2, P2P(fl.fl_addr),bp->b_count, ! 1468: fl.fl_wflag)) ! 1469: goto straddle; ! 1470: ! 1471: else ! 1472: goto command; ! 1473: } ! 1474: ! 1475: if (dmaon(DMA_CH2, P2P(fl.fl_addr), 512, fl.fl_wflag) == 0) { ! 1476: straddle: ! 1477: devmsg(bp->b_dev, "fd: DMA page straddle at %x:%x", ! 1478: fl.fl_addr); ! 1479: dmaunlock(&fldmalck); ! 1480: bp->b_flag |= BFERR; ! 1481: fldone(bp); ! 1482: goto again; ! 1483: } ! 1484: command: ! 1485: dmago(DMA_CH2); ! 1486: fdcPut(flcmd); ! 1487: fdcPut((fl.fl_head<<2) | fl.fl_unit); ! 1488: ! 1489: if (bp->b_req == BFLFMT) { ! 1490: fdcPut(fl.fl_fd[fl.fl_unit].fd_N); /* N */ ! 1491: fdcPut(fl.fl_fd[fl.fl_unit].fd_nspt); /* SC */ ! 1492: fdcPut(fl.fl_fd[fl.fl_unit].fd_FGPL); /* GPL */ ! 1493: fdcPut(0xF6); /* D */ ! 1494: } ! 1495: ! 1496: else { ! 1497: fdcPut(fl.fl_fcyl); ! 1498: fdcPut(fl.fl_head); ! 1499: fdcPut(fl.fl_fsec); ! 1500: fdcPut(fl.fl_fd[fl.fl_unit].fd_N); /* N */ ! 1501: fdcPut(fl.fl_fd[fl.fl_unit].fd_nspt); /* EOT */ ! 1502: fdcPut(fl.fl_fd[fl.fl_unit].fd_GPL[fl.fl_rate_set]); ! 1503: /* GPL */ ! 1504: fdcPut(0xFF); /* DTL */ ! 1505: } ! 1506: ! 1507: fl.fl_state = SENDIO; ! 1508: break; ! 1509: ! 1510: case SENDIO: ! 1511: T_HAL(0x40000, printf("SENDIO ")); ! 1512: fl.fl_time[fl.fl_unit] = 0; ! 1513: dmaoff(DMA_CH2); ! 1514: dmaunlock(&fldmalck); ! 1515: ! 1516: if (fl_clrng_cd) { ! 1517: fl.fl_state = SIDLE; ! 1518: wakeup(&fl.fl_state); ! 1519: goto again; ! 1520: } ! 1521: ! 1522: /* ! 1523: * We now check for errors. If the error is a data ! 1524: * CRC error, we KNOW we're on the correct track, and ! 1525: * we just retry the read once before recalibrating. ! 1526: * We recalibrate for all other errors. ! 1527: */ ! 1528: if ((fdc.fdc_cmdstat[0] & ST0_IC) != ST0_NT) { ! 1529: if (++fl.fl_nerr < 5) { ! 1530: if (fdc.fdc_cmdstat[2] & ST2_DD) { ! 1531: if (fl.fl_nerr & 1) ! 1532: goto SetSEEKState; ! 1533: else ! 1534: goto Ask4Recal; ! 1535: } else { ! 1536: Ask4Recal: ! 1537: fl.fl_incal[fl.fl_unit] = -1; ! 1538: SetSEEKState: ! 1539: fl.fl_state = SSEEK; ! 1540: } ! 1541: } else { ! 1542: fdcStatus(); /* Total failure; */ ! 1543: bp->b_flag |= BFERR; /* we give up. */ ! 1544: fldone(bp); ! 1545: } ! 1546: } ! 1547: ! 1548: else if (--fl.fl_nsec == 0) { ! 1549: bp->b_resid = 0; ! 1550: fldone(bp); ! 1551: } ! 1552: ! 1553: else { ! 1554: ++fl.fl_secn; ! 1555: fl.fl_addr += 512; /* 512 == fl.fl_fd.fd_nbps */ ! 1556: fl.fl_state = SSEEK; ! 1557: } ! 1558: ! 1559: /* ! 1560: * Delay for minimum 1.5 msecs after writing before seek. ! 1561: */ ! 1562: if (fl.fl_wflag) { ! 1563: timeout(&fltim, 2, fldelay, fl.fl_state); ! 1564: fl.fl_state = SDELAY; ! 1565: break; ! 1566: } ! 1567: ! 1568: goto again; ! 1569: ! 1570: case SDELAY: ! 1571: T_HAL(0x40000, printf("SDELAY ")); ! 1572: /* ! 1573: * Ignore interrupts until timeout occurs. ! 1574: */ ! 1575: break; ! 1576: ! 1577: default: ! 1578: panic("fds"); ! 1579: } ! 1580: } ! 1581: ! 1582: /* ! 1583: * Delay before initiating next operation. ! 1584: * This allows the floppy motor to turn on, ! 1585: * the head to settle before writing, ! 1586: * the erase head to turn off after writing, etc. ! 1587: */ ! 1588: static void ! 1589: fldelay(state) ! 1590: int state; ! 1591: { ! 1592: int s; ! 1593: ! 1594: s = sphi(); ! 1595: if (fl.fl_state == SDELAY) { ! 1596: fl.fl_state = state; ! 1597: flfsm(); ! 1598: } ! 1599: spl(s); ! 1600: } ! 1601: ! 1602: /* ! 1603: * The flrate function returns the data rate for the flopen and flfsm routines. ! 1604: */ ! 1605: static int ! 1606: flrate(dev) ! 1607: register dev_t dev; ! 1608: { ! 1609: register int unit = funit(dev); ! 1610: register int rate = frates[fl.fl_type[unit]].fl_hi_rate; ! 1611: ! 1612: if ((rate == -1) || (fdata[fkind(dev)].fd_nspt < 15)) ! 1613: rate = frates[fl.fl_type[unit]].fl_lo_rate; ! 1614: ! 1615: return(rate); ! 1616: } ! 1617: ! 1618: /* ! 1619: * fldone() returns current request to operating system. ! 1620: */ ! 1621: static void ! 1622: fldone(bp) ! 1623: register BUF * bp; ! 1624: { ! 1625: fl.fl_actf = bp->b_actf; ! 1626: fl.fl_state = SIDLE; ! 1627: bdone(bp); ! 1628: wakeup(&fl.fl_state); ! 1629: } ! 1630: ! 1631: /* ! 1632: * The recovery routine resets and reprograms the floppy controller, ! 1633: * and discards any queued requests on the current drive. ! 1634: * This is required if the floppy door is open, or diskette is missing. ! 1635: */ ! 1636: static void ! 1637: flrecov() ! 1638: { ! 1639: register int x; ! 1640: ! 1641: if (fl_dsk_ch_prob) ! 1642: jopen = 1; ! 1643: ! 1644: /* ! 1645: * Disable DMA transfer. ! 1646: * Reset floppy controller. ! 1647: */ ! 1648: dmaoff(DMA_CH2); ! 1649: ! 1650: /* ! 1651: * Unlock the controller if locked by us. ! 1652: */ ! 1653: ! 1654: outb(FDCDOR, 0); ! 1655: fl.fl_state = SIDLE; ! 1656: wakeup(&fl.fl_state); ! 1657: dmaunlock(&fldmalck); /* Ensures 14 clock cycles */ ! 1658: outb(FDCDOR, DORNMR | DORIEN); ! 1659: ! 1660: fl.fl_mstatus = 0; /* No motors on */ ! 1661: fl.fl_selected_unit = -1; /* No unit selected */ ! 1662: ! 1663: /* ! 1664: * Program floppy controller. ! 1665: */ ! 1666: fdcSpecify(fl_srt, fl_hut, fl_hlt); /* Forces wait */ ! 1667: ! 1668: /* ! 1669: * Program transfer bps. ! 1670: */ ! 1671: fdcRate(fl.fl_rate_set); ! 1672: ! 1673: /* ! 1674: * Drives are no longer in calibration. ! 1675: * Was: fl.fl_incal[1] = -1; ! 1676: * Changed to: fl.fl_incal[x] = -1; ! 1677: * -louis 7/93 ! 1678: */ ! 1679: for (x = 0; x < MAXDRVS; x++) ! 1680: fl.fl_incal[x] = -1; ! 1681: ! 1682: /* ! 1683: * Abort all block requests on current drive after 1st recov attempt. ! 1684: */ ! 1685: if (fl.fl_actf) { ! 1686: printf("fd%d: <Door Open>\n", fl.fl_unit); /* Message */ ! 1687: clrQ(fl.fl_actf->b_dev); /* Dump pending reqs. */ ! 1688: fl.fl_dsk_chngd[fl.fl_unit] = 1; /* Make disk changed. */ ! 1689: } ! 1690: ! 1691: /* ! 1692: * Delay before setting controller state to idle. ! 1693: * This gives time for spurious floppy interrupts to occur. ! 1694: * NOTE: Can't call flfsm(), since it may call us (future revision). ! 1695: */ ! 1696: timeout(&fltim, HZ/4, fldelay, SIDLE); ! 1697: fl.fl_state = SDELAY; ! 1698: } ! 1699: ! 1700: /* ! 1701: * This routine is called by the ! 1702: * clock handler every second. If the drive ! 1703: * has been idle for a long time it turns off ! 1704: * the motor and shuts off the timeouts. ! 1705: */ ! 1706: static int ! 1707: fltimeout() ! 1708: { ! 1709: register int unit; ! 1710: register int mask; ! 1711: register int s; ! 1712: ! 1713: s = sphi(); ! 1714: ! 1715: /* ! 1716: * Scan all drives, looking for motor timeouts. ! 1717: */ ! 1718: for (unit=0, mask=0x10; unit < MAXDRVS; unit++, mask <<= 1) { ! 1719: ! 1720: /* ! 1721: * Ignore drives which aren't spinning. ! 1722: */ ! 1723: if ((fl.fl_mstatus & mask) == 0) ! 1724: continue; ! 1725: ! 1726: /* ! 1727: * If timer is disabled (i.e. we are waiting for the DMA ! 1728: * controller), go on to the next drive. ! 1729: */ ! 1730: if (fl.fl_time[unit] < 0) ! 1731: continue; ! 1732: ! 1733: /* ! 1734: * Leave recently accessed (in last 4 seconds) drives spinning. ! 1735: */ ! 1736: if (++fl.fl_time[unit] < MTIMER) ! 1737: continue; ! 1738: ! 1739: /* ! 1740: * Timeout drives which have been inactive for 5 seconds. ! 1741: */ ! 1742: fl.fl_mstatus &= ~mask; ! 1743: if (unit == fl.fl_selected_unit) ! 1744: fl.fl_selected_unit = -1; ! 1745: ! 1746: /* ! 1747: * Not selected drive, or selected drive is idle. ! 1748: */ ! 1749: if ((unit != fl.fl_unit) || (fl.fl_state == SIDLE)) ! 1750: continue; ! 1751: ! 1752: /* ! 1753: * Active drive did not complete operation within 5 seconds. ! 1754: * Attempt recovery. ! 1755: */ ! 1756: flrecov(); ! 1757: ! 1758: /* ! 1759: * Initiate next block request. ! 1760: */ ! 1761: if (fl.fl_state == SIDLE) ! 1762: flfsm(); ! 1763: } ! 1764: ! 1765: /* ! 1766: * Physically turn off drives which timed out. ! 1767: */ ! 1768: outb(FDCDOR, DORNMR | DORIEN | fl.fl_mstatus | fl.fl_unit); ! 1769: ! 1770: /* ! 1771: * Stop checking once all drives have been stopped. ! 1772: */ ! 1773: if (fl.fl_mstatus == 0) ! 1774: setFlTimer(0); ! 1775: ! 1776: spl(s); ! 1777: } ! 1778: ! 1779: static void ! 1780: flDrvSelect() ! 1781: { ! 1782: fl.fl_time[fl.fl_unit] = 0; /* Start motor-on timeout. */ ! 1783: fl.fl_mstatus |= fl.fl_mask; ! 1784: fdcDrvSelect(fl.fl_unit, 1); /* "1" for motor on */ ! 1785: fl.fl_selected_unit = fl.fl_unit; /* This unit is running. */ ! 1786: } ! 1787: ! 1788: /* ! 1789: * Get the drive status ! 1790: */ ! 1791: static void ! 1792: flDrvStatus() ! 1793: { ! 1794: register int b; ! 1795: register int n = 0; /* # of status bytes read */ ! 1796: register int i = 0; /* Timeout count */ ! 1797: register int s; ! 1798: ! 1799: s = sphi(); ! 1800: ! 1801: flDrvSelect(); /* Be sure drive is selected */ ! 1802: ! 1803: /* Issue a sense drive status command. */ ! 1804: fdcDrvStatus(fl.fl_unit, 0); ! 1805: ! 1806: /* Stash Drive Status results. */ ! 1807: for (;;) { ! 1808: /* Check for incoming signal. */ ! 1809: spl(s); ! 1810: if (nondsig()) { /* signal? */ ! 1811: u.u_error = EINTR; ! 1812: break; ! 1813: } ! 1814: s = sphi(); ! 1815: ! 1816: /* Copy data byte from FDC into fl_drvstat array. */ ! 1817: b = fdcGet(); ! 1818: if (b == -1) ! 1819: break; ! 1820: if (n < FL_NUM_DRV_STAT) ! 1821: fl.fl_drvstat[n++] = b; ! 1822: } ! 1823: fl.fl_ndrvstat = n; ! 1824: spl(s); ! 1825: } ! 1826: ! 1827: static void ! 1828: flIntHandler() ! 1829: { ! 1830: /* ! 1831: * Need to get FDC status from result phase, and clear interrupt ! 1832: * that may have been generated by diskette change or seek/recal ! 1833: * complete. ! 1834: */ ! 1835: fdcSense(); ! 1836: ! 1837: if (fl.fl_state != SIDLE) ! 1838: flfsm(); ! 1839: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.