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