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