|
|
1.1 ! root 1: /* ! 2: * This is a driver for the IBM AT (286 & up) floppy, using interrupts and DMA ! 3: * on the NEC 756 floppy chip. ! 4: * Handles single/double/quad density drives, 8/9/15/18 sectors per track. ! 5: * ! 6: * Minor device assignments: xxuuhkkk ! 7: * uu - unit = 0/1/2/3 ! 8: * kkk - kind, struct fdata infra. ! 9: * h - alternating head rather than side by side ! 10: * ! 11: */ ! 12: ! 13: #include <sys/coherent.h> ! 14: #include <sys/buf.h> ! 15: #include <sys/con.h> ! 16: #include <sys/stat.h> ! 17: #include <errno.h> ! 18: #include <sys/timeout.h> ! 19: #include <sys/fdioctl.h> ! 20: #include <sys/sched.h> ! 21: #include <sys/dmac.h> ! 22: #include <sys/devices.h> ! 23: ! 24: #ifdef _I386 ! 25: #include <sys/reg.h> ! 26: #else ! 27: #include <sys/i8086.h> ! 28: #endif ! 29: ! 30: #define BIT(n) (1 << (n)) ! 31: ! 32: /* ! 33: * Patchable parameters (default to IBM PC/XT values). ! 34: */ ! 35: ! 36: int fl_srt = 0xC; /* Floppy seek step rate, in unit 2 millisec */ ! 37: /* NOT DIRECTLY ENCODED */ ! 38: /* COMPAQ wants 0xD */ ! 39: int fl_hlt = 1; /* Floppy head load time, in unit 4 millisec */ ! 40: int fl_hut = 0xF; /* Floppy head unload time, in unit 32 millisec */ ! 41: ! 42: int flload(); ! 43: int flunload(); ! 44: int flopen(); ! 45: int flblock(); ! 46: int flread(); ! 47: int flwrite(); ! 48: int flioctl(); ! 49: int fldelay(); ! 50: int flintr(); ! 51: int fltimeout(); ! 52: int nulldev(); ! 53: int nonedev(); ! 54: ! 55: CON flcon = { ! 56: DFBLK|DFCHR, /* Flags */ ! 57: FL_MAJOR, /* Major index */ ! 58: flopen, /* Open */ ! 59: nulldev, /* Close */ ! 60: flblock, /* Block */ ! 61: flread, /* Read */ ! 62: flwrite, /* Write */ ! 63: flioctl, /* Ioctl */ ! 64: nulldev, /* Powerfail */ ! 65: fltimeout, /* Timeout */ ! 66: flload, /* Load */ ! 67: flunload /* Unload */ ! 68: }; ! 69: ! 70: #define MTIMER 2 /* Motor timeout */ ! 71: #define FDCDOR 0x3F2 /* Digital output */ ! 72: #define FDCDAT 0x3F5 /* Data register */ ! 73: #define FDCMSR 0x3F4 /* Main status register */ ! 74: #define FDCRATE 0x3F7 /* Transfer rate (500,300,250 Kbps) */ ! 75: ! 76: #define DORDS 0x03 /* Drive select bits */ ! 77: #define DORNMR 0x04 /* Not master reset */ ! 78: #define DORIEN 0x08 /* Interrupt, DMA enable */ ! 79: #define DORMS 0xF0 /* Motor enables */ ! 80: ! 81: #define MSRDB 0x0F /* Drive busy */ ! 82: #define MSRCB 0x10 /* Control busy */ ! 83: #define MSRNDMA 0x20 /* Not DMA */ ! 84: #define MSRDIO 0x40 /* Data direction */ ! 85: #define MSRRQM 0x80 /* Request for master */ ! 86: ! 87: /* ! 88: * Status Register 0 - Bit Definitions. ! 89: */ ! 90: #define ST0_US0 0x01 /* Unit Select 0 */ ! 91: #define ST0_US1 0x02 /* Unit Select 1 */ ! 92: #define ST0_HD 0x04 /* Head Address */ ! 93: #define ST0_NR 0x08 /* Not Ready */ ! 94: #define ST0_EC 0x10 /* Equipment Check */ ! 95: #define ST0_SE 0x20 /* Seek End */ ! 96: #define ST0_IC 0xC0 /* Interrupt code */ ! 97: #define ST0_NT 0x00 /* Normal Termination */ ! 98: ! 99: /* ! 100: * Status Register 1 - Bit Definitions. ! 101: */ ! 102: #define ST1_MA 0x01 /* Missing Address Mark */ ! 103: #define ST1_NW 0x02 /* Not writeable */ ! 104: #define ST1_ND 0x04 /* No Data */ ! 105: /* 0x08 */ /* Not used - always 0 */ ! 106: #define ST1_OR 0x10 /* Overrun */ ! 107: #define ST1_DE 0x20 /* Data Error */ ! 108: /* 0x40 */ /* Not used - always 0 */ ! 109: #define ST1_EN 0x80 /* End of Cylinder */ ! 110: ! 111: /* ! 112: * Status Register 2 - Bit Definitions. ! 113: */ ! 114: #define ST2_MD 0x01 /* Missing Address Mark in Data Field */ ! 115: #define ST2_BC 0x02 /* Bad Cylinder */ ! 116: #define ST2_SN 0x04 /* Scan Not Satisfied */ ! 117: #define ST2_SH 0x08 /* Scan Equal Hit */ ! 118: #define ST2_WC 0x10 /* Wrong Cylinder */ ! 119: #define ST2_DD 0x20 /* Data Error in Data Field */ ! 120: #define ST2_CM 0x40 /* Control Mark */ ! 121: /* 0x80 */ /* Not used - always 0 */ ! 122: ! 123: /* ! 124: * Status Register 3 - Bit Definitions. ! 125: */ ! 126: #define ST3_US0 0x01 /* Unit Select 0 */ ! 127: #define ST3_US1 0x02 /* Unit Select 1 */ ! 128: #define ST3_HD 0x04 /* Head Address */ ! 129: #define ST3_TS 0x08 /* Two Sides */ ! 130: #define ST3_T0 0x10 /* Track 0 */ ! 131: #define ST3_RDY 0x20 /* Ready */ ! 132: #define ST3_WP 0x40 /* Write Protected */ ! 133: #define ST3_FT 0x80 /* Fault */ ! 134: ! 135: /* ! 136: * Controller Commands. ! 137: */ ! 138: #define CMDSPEC 0x03 /* Specify */ ! 139: #define CMDRCAL 0x07 /* Recal */ ! 140: #define CMDSEEK 0x0F /* Seek */ ! 141: #define CMDRDAT 0x66 /* Read data */ ! 142: #define CMDWDAT 0x45 /* Write data */ ! 143: #define CMDSINT 0x08 /* Sense status */ ! 144: #define CMDFMT 0x4D /* Format track */ ! 145: ! 146: /* ! 147: * Driver States. ! 148: */ ! 149: #define SIDLE 0 /* Idle */ ! 150: #define SSEEK 1 /* Need seek */ ! 151: #define SRDWR 2 /* Need read/write command */ ! 152: #define SENDIO 3 /* Need end I/O processing */ ! 153: #define SDELAY 4 /* Delay before next disk operation */ ! 154: #define SHDLY 5 /* Head settling delay before r/w */ ! 155: #define SLOCK 6 /* Got DMA controller lock */ ! 156: ! 157: #define funit(x) (minor(x)>>4) /* Unit/drive number */ ! 158: #define fkind(x) (minor(x)&0x7) /* Kind of format */ ! 159: #define fhbyh(x) (minor(x)&0x8) /* 0=Side by side, 1=Head by head */ ! 160: ! 161: static ! 162: struct fdata { ! 163: int fd_size; /* Blocks per diskette */ ! 164: int fd_nhds; /* Heads per drive */ ! 165: int fd_trks; /* Tracks per side */ ! 166: int fd_offs; /* Sector base */ ! 167: int fd_nspt; /* Sectors per track */ ! 168: char fd_GPL[4]; /* Controller gap param (indexed by rate) */ ! 169: char fd_N; /* Controller size param */ ! 170: char fd_FGPL; /* Format gap length */ ! 171: } fdata[] = { ! 172: /* 8 sectors per track, surface by surface seek. */ ! 173: { 320,1,40,0, 8, { 0x00,0x23,0x2A }, 2,0x50 }, /* Single sided */ ! 174: { 640,2,40,0, 8, { 0x00,0x23,0x2A }, 2,0x50 }, /* Double sided */ ! 175: { 1280,2,80,0, 8, { 0x00,0x23,0x2A }, 2,0x50 }, /* Quad density */ ! 176: /* 9 sectors per track, surface by surface seek. */ ! 177: { 360,1,40,0, 9, { 0x00,0x23,0x2A }, 2,0x50 }, /* Single sided */ ! 178: { 720,2,40,0, 9, { 0x00,0x23,0x2A }, 2,0x50 }, /* Double sided */ ! 179: { 1440,2,80,0, 9, { 0x00,0x23,0x2A }, 2,0x50 }, /* Quad density */ ! 180: /* 15 sectors per track, surface by surface seek. */ ! 181: { 2400,2,80,0,15, { 0x1B,0x00,0x00 }, 2,0x54 }, /* High capacity */ ! 182: /* 18 sectors per track, surface by surface seek. */ ! 183: { 2880,2,80,0,18, { 0x1B,0x00,0x00 }, 2,0x54 } /* 1.44 3.5" */ ! 184: }; ! 185: ! 186: ! 187: static ! 188: struct fl { ! 189: BUF *fl_actf; /* Queue, forward */ ! 190: BUF *fl_actl; /* Queue, backward */ ! 191: paddr_t fl_addr; /* Address */ ! 192: int fl_nsec; /* # of sectors */ ! 193: int fl_secn; /* Current sector */ ! 194: struct fdata fl_fd; /* Disk kind data */ ! 195: int fl_fcyl; /* Floppy cylinder # */ ! 196: char fl_incal[4]; /* Disk in cal flags */ ! 197: char fl_ndsk; /* # of 5 1/4" drives */ ! 198: char fl_unit; /* Unit # */ ! 199: char fl_mask; /* Handy unit mask */ ! 200: char fl_hbyh; /* 0/1 = Side by side/Head by head */ ! 201: char fl_nerr; /* Error count */ ! 202: int fl_ncmdstat; /* Number of cmd status bytes recvd */ ! 203: char fl_cmdstat[8]; /* Command Status buffer */ ! 204: int fl_nintstat; /* Number of intr status bytes recvd */ ! 205: char fl_intstat[4]; /* Interrupt Status buffer */ ! 206: int fl_fsec; /* Floppy sector # */ ! 207: int fl_head; /* Floppy head */ ! 208: char fl_init; /* FDC init done flag */ ! 209: char fl_state; /* Processing state */ ! 210: char fl_mstatus; /* Motor status */ ! 211: char fl_time[4]; /* Motor timeout */ ! 212: char fl_rate; /* Data rate: 500,300,250,?? kbps */ ! 213: char fl_type[4]; /* Type of drive: 2 = HiCap */ ! 214: int fl_wflag; /* Write operation */ ! 215: int fl_recov; /* Recovery initiated */ ! 216: } fl; ! 217: ! 218: static BUF flbuf; ! 219: static TIM fltim; ! 220: static TIM fldmalck; /* DMA lock deferred function structure. */ ! 221: ! 222: /* ! 223: * The load routine asks the ! 224: * switches how many drives are present ! 225: * in the machine, and sets up the field ! 226: * in the floppy database. It also grabs ! 227: * the level 6 interrupt vector. ! 228: */ ! 229: static ! 230: flload() ! 231: { ! 232: register int eflag; ! 233: register int s; ! 234: ! 235: /* ! 236: * Ensure DMA channel 2 is turned off. ! 237: * The Computerland ROM does not disable DMA channel after autoboot ! 238: * from hard disk. The Western Digital controller board appears to ! 239: * send a dma burst when the floppy controller chip is reset. ! 240: */ ! 241: dmaoff( 2 ); ! 242: ! 243: /* ! 244: * Read floppy equipment byte from CMOS ram ! 245: * drive 0 is in high nibble, drive 1 is in low nibble. ! 246: */ ! 247: outb( 0x70, 0x10 ); ! 248: /* delay */ ! 249: eflag = inb( 0x71 ); ! 250: ! 251: /* ! 252: * Flag hardware as an IBM AT if neither equipment byte nibble is ! 253: * greater than 4 (since 5 through 15 are reserved nibble values - see ! 254: * IBM AT Technical Reference manual, page 1-50). Note that this ! 255: * relies on the fact that in the XT, this byte will "float" high. ! 256: * NOTE: 1.44 Mbyte 3.5 inch drives are type 4 ! 257: */ ! 258: if ( (eflag & 0x88) == 0 ) { ! 259: ! 260: /* ! 261: * Reinitialize patchable parameters for IBM AT. ! 262: */ ! 263: fl_srt = 0xD; /* Floppy seek step rate, in unit 2 ms */ ! 264: /* NOT DIRECTLY ENCODED */ ! 265: fl_hlt = 25; /* Floppy head load time, in unit 4 ms */ ! 266: ! 267: /* ! 268: * Define AT drive information. ! 269: */ ! 270: fl.fl_type[0] = eflag >> 4; ! 271: fl.fl_type[1] = eflag & 15; ! 272: fl.fl_rate = 1; /* Must not be 2 */ ! 273: ! 274: /* ! 275: * Determine number of AT floppy drives. ! 276: */ ! 277: if ( eflag & 0xF0 ) { ! 278: fl.fl_ndsk++; ! 279: if ( eflag & 0x0F ) ! 280: fl.fl_ndsk++; ! 281: } ! 282: } else { ! 283: /* ! 284: * Define XT drive information. ! 285: */ ! 286: eflag = int11(); ! 287: fl.fl_rate = 2; ! 288: if ( eflag & 1 ) ! 289: fl.fl_ndsk = ((eflag >> 6) & 0x03) + 1; ! 290: } ! 291: ! 292: if ( fl.fl_ndsk ) { ! 293: ! 294: s = sphi(); ! 295: outb(FDCDOR, 0); ! 296: setivec(6, &flintr); ! 297: ! 298: outb(FDCDOR, 0); ! 299: outb(FDCDOR, DORNMR); ! 300: ! 301: if ( fl.fl_rate != 2 ) ! 302: outb(FDCRATE, fl.fl_rate ); ! 303: ! 304: flput(CMDSPEC); ! 305: flput((fl_srt<<4)|fl_hut); ! 306: flput(fl_hlt<<1); ! 307: spl( s ); ! 308: } ! 309: } ! 310: ! 311: /* ! 312: * Release resources. ! 313: */ ! 314: flunload() ! 315: { ! 316: /* ! 317: * Clear interrupt vector. ! 318: */ ! 319: if ( fl.fl_ndsk ) ! 320: clrivec(6); ! 321: ! 322: /* ! 323: * Cancel timed function. ! 324: */ ! 325: timeout( &fltim, 0, NULL, NULL ); ! 326: ! 327: /* ! 328: * Cancel periodic [1 second] invocation. ! 329: */ ! 330: drvl[FL_MAJOR].d_time = 0; ! 331: ! 332: /* ! 333: * Turn motors off. ! 334: */ ! 335: outb(FDCDOR, DORNMR | DORIEN ); ! 336: } ! 337: ! 338: /* ! 339: * The open routine screens out ! 340: * opens of illegal minor devices and ! 341: * performs the NEC specify command if ! 342: * this is the very first floppy disk ! 343: * open call. ! 344: */ ! 345: ! 346: static ! 347: flopen( dev, mode ) ! 348: ! 349: dev_t dev; ! 350: int mode; ! 351: ! 352: { ! 353: /* ! 354: * Validate existence and data rate [Gap length != 0]. ! 355: */ ! 356: if ( ( funit(dev) >= fl.fl_ndsk ) ! 357: || ( fdata[ fkind(dev) ].fd_GPL[ flrate(dev) ] == 0 ) ) { ! 358: ! 359: u.u_error = ENXIO; ! 360: return; ! 361: } ! 362: } ! 363: ! 364: /* ! 365: * The read routine just calls ! 366: * off to the common raw I/O processing ! 367: * code, using a static buffer header in ! 368: * the driver. ! 369: */ ! 370: ! 371: static ! 372: flread( dev, iop ) ! 373: ! 374: dev_t dev; ! 375: IO *iop; ! 376: ! 377: { ! 378: dmareq(&flbuf, iop, dev, BREAD); ! 379: } ! 380: ! 381: /* ! 382: * The write routine is just like the ! 383: * read routine, except that the function code ! 384: * is write instead of read. ! 385: */ ! 386: ! 387: static ! 388: flwrite( dev, iop ) ! 389: ! 390: dev_t dev; ! 391: IO *iop; ! 392: ! 393: { ! 394: dmareq(&flbuf, iop, dev, BWRITE); ! 395: } ! 396: ! 397: /* ! 398: * The ioctl routine simply queues a format request ! 399: * using flbuf. ! 400: * The only valid command is to format a track. ! 401: * The parameter block contains the header records supplied to the controller. ! 402: */ ! 403: ! 404: static ! 405: flioctl( dev, com, par ) ! 406: ! 407: dev_t dev; ! 408: int com; ! 409: char *par; ! 410: ! 411: { ! 412: register unsigned s; ! 413: register struct fdata *fdp; ! 414: unsigned hd, cyl; ! 415: ! 416: if (com != FDFORMAT) { ! 417: u.u_error = EINVAL; ! 418: return; ! 419: } ! 420: ! 421: fdp = &fdata[ fkind(dev) ]; ! 422: cyl = getubd(par); ! 423: hd = getubd(par+1); ! 424: ! 425: if (hd > 1 || cyl >= fdp->fd_trks) { ! 426: u.u_error = EINVAL; ! 427: return; ! 428: } ! 429: ! 430: /* ! 431: * The following may need some explanation. ! 432: * dmareq will: ! 433: * claim the buffer, ! 434: * bounds check the parameter buffer, ! 435: * lock the parameter buffer in memory, ! 436: * convert io_seek to b_bno, ! 437: * dispatch the request, ! 438: * wait for completion, ! 439: * and unlock the parameter buffer. ! 440: * The b_bno is reconverted to hd, cyl in flfsm. ! 441: */ ! 442: ! 443: s = fhbyh(dev) ? (cyl * fdp->fd_nhds + hd) : (hd * fdp->fd_trks + cyl); ! 444: s *= fdp->fd_nspt; ! 445: u.u_io.io_seek = ((long)s) * BSIZE; ! 446: #ifdef _I386 ! 447: u.u_io.io.vbase = par; ! 448: #else ! 449: u.u_io.io_base = par; ! 450: #endif ! 451: u.u_io.io_ioc = fdp->fd_nspt * 4; ! 452: dmareq(&flbuf, &u.u_io, dev, FDFORMAT); ! 453: } ! 454: ! 455: /* ! 456: * Start up block I/O on a ! 457: * buffer. Check that the block number ! 458: * is not out of range, given the style of ! 459: * the disk. Put the buffer header into the ! 460: * device queue. Start up the disk if the ! 461: * device is idle. ! 462: */ ! 463: ! 464: static ! 465: flblock( bp ) ! 466: ! 467: register BUF *bp; ! 468: ! 469: { ! 470: register int s; ! 471: register unsigned bno; ! 472: ! 473: bno = bp->b_bno + (bp->b_count >> 9) - 1; ! 474: if ((unsigned)bp->b_bno > fdata[ fkind(bp->b_dev) ].fd_size) { ! 475: bp->b_flag |= BFERR; ! 476: bdone(bp); ! 477: return; ! 478: } ! 479: ! 480: if (bp->b_req != FDFORMAT && bno >= fdata[ fkind(bp->b_dev) ].fd_size) { ! 481: bp->b_resid = bp->b_count; ! 482: if (bp->b_flag & BFRAW) ! 483: bp->b_flag |= BFERR; ! 484: bdone(bp); /* return w/ b_resid != 0 */ ! 485: return; ! 486: } ! 487: ! 488: if ((bp->b_count&0x1FF) != 0) { ! 489: if (bp->b_req != FDFORMAT) { ! 490: bp->b_flag |= BFERR; ! 491: bdone(bp); ! 492: return; ! 493: } ! 494: } ! 495: ! 496: bp->b_actf = NULL; ! 497: s = sphi(); /* s was already == sphi() on at least PC/XT. */ ! 498: ! 499: if (fl.fl_actf == NULL) ! 500: fl.fl_actf = bp; ! 501: else ! 502: fl.fl_actl->b_actf = bp; ! 503: ! 504: fl.fl_actl = bp; ! 505: ! 506: if (fl.fl_state == SIDLE) ! 507: flfsm(); ! 508: ! 509: spl( s ); ! 510: } ! 511: ! 512: /* ! 513: * This finite state machine is ! 514: * responsible for all sequencing on the disk. ! 515: * It builds the commands, does the seeks, spins up ! 516: * the drive motor for 1 second on the first call, ! 517: * and so on. ! 518: * Note that the format command is rather obscurely shoehorned into this. ! 519: */ ! 520: ! 521: static ! 522: flfsm() ! 523: { ! 524: register BUF *bp; ! 525: register int flcmd; ! 526: register int i; ! 527: ! 528: again: ! 529: bp = fl.fl_actf; ! 530: ! 531: switch (fl.fl_state) { ! 532: ! 533: case SIDLE: ! 534: drvl[FL_MAJOR].d_time = 1; ! 535: ! 536: if ( bp == NULL ) ! 537: break; ! 538: ! 539: fl.fl_fd = fdata[ fkind(bp->b_dev) ]; ! 540: fl.fl_unit = funit( bp->b_dev ); ! 541: fl.fl_hbyh = fhbyh( bp->b_dev ); ! 542: ! 543: fl.fl_mask = 0x10 << fl.fl_unit; ! 544: ! 545: fl.fl_addr = bp->b_paddr; ! 546: fl.fl_secn = bp->b_bno; ! 547: fl.fl_time[fl.fl_unit] = 0; ! 548: ! 549: if ((fl.fl_nsec = bp->b_count>>9) == 0) ! 550: fl.fl_nsec = 1; ! 551: ! 552: fl.fl_nerr = 0; ! 553: ! 554: /* ! 555: * Set data rate if changed. ! 556: * NOTE: XT never changes data rate. ! 557: */ ! 558: if ( (i = flrate(bp->b_dev)) != fl.fl_rate ) ! 559: outb(FDCRATE, fl.fl_rate = i ); ! 560: ! 561: /* ! 562: * Motor is turned off - turn it on, wait 1 second. ! 563: */ ! 564: if ((fl.fl_mstatus&fl.fl_mask) == 0) { ! 565: ! 566: fl.fl_mstatus |= fl.fl_mask; ! 567: outb(FDCDOR, DORNMR|DORIEN|fl.fl_mstatus|fl.fl_unit); ! 568: flsense(); ! 569: ! 570: timeout( &fltim, HZ, fldelay, SSEEK ); ! 571: fl.fl_time[fl.fl_unit] = 0; ! 572: fl.fl_state = SDELAY; ! 573: break; ! 574: } ! 575: /* no break */ ! 576: ! 577: case SSEEK: ! 578: fl.fl_time[fl.fl_unit] = 0; ! 579: outb(FDCDOR, DORNMR|DORIEN|fl.fl_mstatus|fl.fl_unit); ! 580: flsense(); ! 581: ! 582: /* ! 583: * Drive is not calibrated - seek to track 0. ! 584: */ ! 585: if (fl.fl_incal[fl.fl_unit] == 0) { ! 586: ++fl.fl_incal[fl.fl_unit]; ! 587: flput(CMDRCAL); ! 588: flput(fl.fl_unit); ! 589: fl.fl_state = SSEEK; ! 590: break; ! 591: } ! 592: ! 593: fl.fl_fsec = (fl.fl_secn % fl.fl_fd.fd_nspt) + 1; ! 594: ! 595: /* ! 596: * Seek cylinder by cylinder (XENIX/DOS compatible). ! 597: */ ! 598: if (fl.fl_hbyh) { ! 599: fl.fl_head = fl.fl_secn / fl.fl_fd.fd_nspt; ! 600: fl.fl_fcyl = fl.fl_head / fl.fl_fd.fd_nhds; ! 601: fl.fl_head = fl.fl_head % fl.fl_fd.fd_nhds; ! 602: } ! 603: ! 604: /* ! 605: * Seek surface by surface. ! 606: */ ! 607: else { ! 608: fl.fl_fcyl = fl.fl_secn / fl.fl_fd.fd_nspt; ! 609: fl.fl_head = fl.fl_fcyl / fl.fl_fd.fd_trks; ! 610: fl.fl_fcyl = fl.fl_fcyl % fl.fl_fd.fd_trks; ! 611: } ! 612: ! 613: flput(CMDSEEK); ! 614: flput((fl.fl_head<<2) | fl.fl_unit); ! 615: ! 616: if ( fl.fl_fd.fd_trks == 80 ) ! 617: flput(fl.fl_fcyl); ! 618: else if ( fl.fl_type[fl.fl_unit] == 2 ) ! 619: flput(fl.fl_fcyl << 1); /* double step */ ! 620: else if ( fl.fl_type[fl.fl_unit] == 4 ) ! 621: flput(fl.fl_fcyl << 1); /* double step */ ! 622: else ! 623: flput(fl.fl_fcyl); ! 624: ! 625: fl.fl_state = SHDLY; ! 626: break; ! 627: ! 628: case SHDLY: ! 629: /* ! 630: * Delay for minimum 15 milliseconds after seek before w/fmt. ! 631: * 2 clock ticks would give 10-20 millisecond [100 Hz clock]. ! 632: * 3 clock ticks gives 20-30 millisecond [100 Hz clock]. ! 633: */ ! 634: if ( bp->b_req != BREAD ) { ! 635: timeout( &fltim, 3, fldelay, SRDWR ); ! 636: fl.fl_state = SDELAY; ! 637: break; ! 638: } ! 639: /* no break */ ! 640: ! 641: case SRDWR: ! 642: /* ! 643: * Disable watchdog timer while waiting to lock DMA controller. ! 644: */ ! 645: fl.fl_time[fl.fl_unit] = -1; ! 646: ! 647: /* ! 648: * Next state will be DMA locked state. ! 649: */ ! 650: fl.fl_state = SLOCK; ! 651: ! 652: /* ! 653: * If DMA controller locked by someone else, exit for now. ! 654: */ ! 655: if ( dmalock( &fldmalck, flfsm, 0 ) != 0 ) ! 656: return; ! 657: ! 658: case SLOCK: ! 659: /* ! 660: * Reset watchdog timer to restart timeout sequence. ! 661: */ ! 662: fl.fl_time[fl.fl_unit] = 0; ! 663: ! 664: flcmd = CMDRDAT; ! 665: fl.fl_wflag = 0; ! 666: ! 667: if (bp->b_req == BREAD) ! 668: ; ! 669: ! 670: else if (bp->b_req == BWRITE) { ! 671: fl.fl_wflag = 1; ! 672: flcmd = CMDWDAT; ! 673: } ! 674: ! 675: else { ! 676: fl.fl_wflag = 1; ! 677: flcmd = CMDFMT; ! 678: ! 679: #ifdef _I386 ! 680: if(!dmaon(2, P2P(fl.fl_addr),bp->b_count,fl.fl_wflag)) ! 681: #else ! 682: if(dmaon(2, fl.fl_addr, bp->b_count, fl.fl_wflag) == 0) ! 683: #endif ! 684: goto straddle; ! 685: ! 686: else ! 687: goto command; ! 688: } ! 689: ! 690: #ifdef _I386 ! 691: if (dmaon(2, P2P(fl.fl_addr), 512, fl.fl_wflag) == 0) { ! 692: #else ! 693: if (dmaon(2, fl.fl_addr, 512, fl.fl_wflag) == 0) { ! 694: #endif ! 695: straddle: ! 696: devmsg(bp->b_dev, "fd: DMA page straddle at %x:%x", ! 697: fl.fl_addr); ! 698: dmaunlock( &fldmalck ); ! 699: bp->b_flag |= BFERR; ! 700: fldone( bp ); ! 701: goto again; ! 702: } ! 703: command: ! 704: dmago(2); ! 705: flput(flcmd); ! 706: flput((fl.fl_head<<2) | fl.fl_unit); ! 707: ! 708: if (bp->b_req == FDFORMAT) { ! 709: flput(fl.fl_fd.fd_N); /* N */ ! 710: flput(fl.fl_fd.fd_nspt); /* SC */ ! 711: flput(fl.fl_fd.fd_FGPL); /* GPL */ ! 712: flput(0xF6); /* D */ ! 713: } ! 714: ! 715: else { ! 716: flput(fl.fl_fcyl); ! 717: flput(fl.fl_head); ! 718: flput(fl.fl_fsec); ! 719: flput(fl.fl_fd.fd_N); /* N */ ! 720: flput(fl.fl_fd.fd_nspt); /* EOT */ ! 721: flput(fl.fl_fd.fd_GPL[fl.fl_rate]); /* GPL */ ! 722: flput(0xFF); /* DTL */ ! 723: } ! 724: ! 725: fl.fl_state = SENDIO; ! 726: break; ! 727: ! 728: case SENDIO: ! 729: fl.fl_time[fl.fl_unit] = 0; ! 730: dmaoff(2); ! 731: dmaunlock( &fldmalck ); ! 732: ! 733: if ((fl.fl_cmdstat[0]&ST0_IC) != ST0_NT) { ! 734: if (++fl.fl_nerr < 5) { ! 735: fl.fl_incal[fl.fl_unit] = 0; ! 736: fl.fl_state = SSEEK; ! 737: } ! 738: ! 739: else { ! 740: flstatus(); ! 741: bp->b_flag |= BFERR; ! 742: fldone(bp); ! 743: } ! 744: } ! 745: ! 746: else if (--fl.fl_nsec == 0) { ! 747: bp->b_resid = 0; ! 748: fldone(bp); ! 749: } ! 750: ! 751: else { ! 752: ++fl.fl_secn; ! 753: fl.fl_addr += 512; /* 512 == fl.fl_fd.fd_nbps */ ! 754: fl.fl_state = SSEEK; ! 755: } ! 756: ! 757: /* ! 758: * Delay for minimum 1.5 msecs after writing before seek. ! 759: */ ! 760: if ( fl.fl_wflag ) { ! 761: timeout( &fltim, 2, fldelay, fl.fl_state ); ! 762: fl.fl_state = SDELAY; ! 763: break; ! 764: } ! 765: ! 766: goto again; ! 767: ! 768: case SDELAY: ! 769: /* ! 770: * Ignore interrupts until timeout occurs. ! 771: */ ! 772: break; ! 773: ! 774: default: ! 775: panic("fds"); ! 776: } ! 777: } ! 778: ! 779: /* ! 780: * Delay before initiating next operation. ! 781: * This allows the floppy motor to turn on, ! 782: * the head to settle before writing, ! 783: * the erase head to turn off after writing, etc. ! 784: */ ! 785: static ! 786: fldelay( state ) ! 787: int state; ! 788: { ! 789: int s; ! 790: ! 791: s = sphi(); ! 792: if ( fl.fl_state == SDELAY ) { ! 793: fl.fl_state = state; ! 794: flfsm(); ! 795: } ! 796: spl( s ); ! 797: } ! 798: ! 799: /* ! 800: * The flrate function returns the data rate for the flopen and flfsm routines. ! 801: */ ! 802: static int ! 803: flrate( dev ) ! 804: register dev_t dev; ! 805: { ! 806: register int rate; ! 807: ! 808: /* ! 809: * Default is 250 Kbps. ! 810: */ ! 811: rate = 2; ! 812: ! 813: /* ! 814: * Check for high capacity drive. ! 815: */ ! 816: if ( fl.fl_type[ funit(dev) ] == 2 ) { ! 817: ! 818: /* ! 819: * 300 Kbps. ! 820: */ ! 821: rate--; ! 822: ! 823: /* ! 824: * Check for high capacity media. ! 825: */ ! 826: if ( fdata[ fkind(dev) ].fd_nspt == 15 ) { ! 827: ! 828: /* ! 829: * 500 Kbps. ! 830: */ ! 831: rate--; ! 832: } ! 833: } else if (fl.fl_type[funit(dev)] == 4 && fkind(dev) == 7) ! 834: rate = 0; ! 835: ! 836: return( rate ); ! 837: } ! 838: ! 839: /* ! 840: * This routine is called by the ! 841: * clock handler every second. If the drive ! 842: * has been idle for a long time it turns off ! 843: * the motor and shuts off the timeouts. ! 844: */ ! 845: ! 846: static ! 847: fltimeout() ! 848: { ! 849: register int unit; ! 850: register int mask; ! 851: register int s; ! 852: ! 853: s = sphi(); ! 854: ! 855: /* ! 856: * Scan all drives, looking for motor timeouts. ! 857: */ ! 858: for ( unit=0, mask=0x10; unit < 4; unit++, mask <<= 1 ) { ! 859: ! 860: /* ! 861: * Ignore drives which aren't spinning. ! 862: */ ! 863: if ( (fl.fl_mstatus & mask) == 0 ) ! 864: continue; ! 865: ! 866: /* ! 867: * If timer is disabled (i.e. we are waiting for the DMA ! 868: * controller), go on to the next drive. ! 869: */ ! 870: if ( fl.fl_time[unit] < 0 ) ! 871: continue; ! 872: ! 873: /* ! 874: * Leave recently accessed (in last 4 seconds) drives spinning. ! 875: */ ! 876: if ( ++fl.fl_time[unit] < MTIMER ) ! 877: continue; ! 878: ! 879: /* ! 880: * Timeout drives which have been inactive for 5 seconds. ! 881: */ ! 882: fl.fl_mstatus &= ~mask; ! 883: ! 884: /* ! 885: * Not selected drive, or selected drive is idle. ! 886: */ ! 887: if ( (unit != fl.fl_unit) || (fl.fl_state == SIDLE) ) ! 888: continue; ! 889: ! 890: /* ! 891: * Active drive did not complete operation within 5 seconds. ! 892: * Attempt recovery. ! 893: */ ! 894: flrecov(); ! 895: ! 896: /* ! 897: * Initiate next block request. ! 898: */ ! 899: if ( fl.fl_state == SIDLE ) ! 900: flfsm(); ! 901: } ! 902: ! 903: /* ! 904: * Physically turn off drives which timed out. ! 905: */ ! 906: outb(FDCDOR, DORNMR | DORIEN | fl.fl_mstatus | fl.fl_unit); ! 907: ! 908: /* ! 909: * Stop checking once all drives have been stopped. ! 910: */ ! 911: if ( fl.fl_mstatus == 0 ) ! 912: drvl[FL_MAJOR].d_time = 0; ! 913: ! 914: spl(s); ! 915: } ! 916: ! 917: /* ! 918: * The recovery routine resets and reprograms the floppy controller, ! 919: * and discards any queued requests on the current drive. ! 920: * This is required if the floppy door is open, or diskette is missing. ! 921: */ ! 922: ! 923: flrecov() ! 924: { ! 925: register BUF * bp; ! 926: register dev_t dev; ! 927: ! 928: /* ! 929: * Disable DMA transfer. ! 930: * Reset floppy controller. ! 931: */ ! 932: dmaoff( 2 ); ! 933: ! 934: /* ! 935: * Unlock the controller if locked by us. ! 936: */ ! 937: dmaunlock( &fldmalck ); ! 938: ! 939: outb(FDCDOR, 0); ! 940: outb(FDCDOR, DORNMR); ! 941: ! 942: /* ! 943: * Program transfer bps. ! 944: */ ! 945: if ( fl.fl_rate != 2 ) ! 946: outb( FDCRATE, fl.fl_rate ); ! 947: ! 948: /* ! 949: * Program floppy controller. ! 950: */ ! 951: flput( CMDSPEC ); ! 952: flput( (fl_srt << 4) | fl_hut ); ! 953: flput( fl_hlt << 1 ); ! 954: ! 955: /* ! 956: * Drives are no longer in calibration. ! 957: */ ! 958: fl.fl_incal[0] = ! 959: fl.fl_incal[1] = ! 960: fl.fl_incal[2] = ! 961: fl.fl_incal[3] = 0; ! 962: ! 963: /* ! 964: * Abort all block requests on current drive after 1st recov attempt. ! 965: */ ! 966: if ( bp = fl.fl_actf ) { ! 967: printf("fd%d: <Door Open>\n", fl.fl_unit ); ! 968: dev = bp->b_dev; ! 969: do { ! 970: bp->b_flag |= BFERR; ! 971: fldone( bp ); ! 972: } while ( (bp = fl.fl_actf) && (bp->b_dev == dev) ); ! 973: } ! 974: ! 975: /* ! 976: * Delay before setting controller state to idle. ! 977: * This gives time for spurious floppy interrupts to occur. ! 978: * NOTE: Can't call flfsm(), since it may call us [future revision]. ! 979: */ ! 980: timeout( &fltim, HZ/4, fldelay, SIDLE ); ! 981: fl.fl_state = SDELAY; ! 982: } ! 983: ! 984: /* ! 985: * The interrupt routine gets all ! 986: * the status bytes the controller chip ! 987: * will give it, then issues a sense interrupt ! 988: * status command (which is necessary for a seek ! 989: * to complete!) and throws all of the status ! 990: * bytes away. ! 991: */ ! 992: ! 993: static ! 994: flintr() ! 995: { ! 996: register int s; ! 997: ! 998: s = sphi(); ! 999: flsense(); ! 1000: ! 1001: if (fl.fl_state != SIDLE) ! 1002: flfsm(); ! 1003: ! 1004: spl(s); ! 1005: } ! 1006: ! 1007: /* ! 1008: * Fldone() returns current request to operating system. ! 1009: */ ! 1010: fldone( bp ) ! 1011: register BUF * bp; ! 1012: { ! 1013: fl.fl_actf = bp->b_actf; ! 1014: fl.fl_state = SIDLE; ! 1015: bdone( bp ); ! 1016: } ! 1017: ! 1018: /* ! 1019: * Flsense() issues a sense interrupt status command ! 1020: * to restore the controller to a quiescent state. ! 1021: */ ! 1022: ! 1023: static ! 1024: flsense() ! 1025: { ! 1026: register int b; ! 1027: register int n; ! 1028: register int i = 0; ! 1029: register int s; ! 1030: ! 1031: s = sphi(); ! 1032: ! 1033: /* ! 1034: * Read all the status bytes the controller will give us. ! 1035: */ ! 1036: n = 0; ! 1037: ! 1038: for (;;) { ! 1039: while (((b=inb(FDCMSR))&MSRRQM) == 0) { ! 1040: if ( --i == 0 ) { ! 1041: printf("flintr: timeout\n"); ! 1042: break; ! 1043: } ! 1044: } ! 1045: ! 1046: if ((b&MSRDIO) == 0) ! 1047: break; ! 1048: ! 1049: b = inb(FDCDAT); ! 1050: if ( n < sizeof(fl.fl_cmdstat) ) ! 1051: fl.fl_cmdstat[n++] = b; ! 1052: } ! 1053: ! 1054: fl.fl_ncmdstat = n; ! 1055: ! 1056: /* ! 1057: * Issue a sense interrupt command and discard result. ! 1058: */ ! 1059: outb(FDCDAT, CMDSINT); ! 1060: ! 1061: n = 0; ! 1062: for (;;) { ! 1063: while (((b=inb(FDCMSR))&MSRRQM) == 0) { ! 1064: if ( --i == 0 ) { ! 1065: printf("flsense: timeout\n"); ! 1066: break; ! 1067: } ! 1068: } ! 1069: ! 1070: if ((b&MSRDIO) == 0) ! 1071: break; ! 1072: ! 1073: b = inb(FDCDAT); ! 1074: if ( n < sizeof(fl.fl_intstat) ) ! 1075: fl.fl_intstat[n++] = b; ! 1076: } ! 1077: fl.fl_nintstat = n; ! 1078: ! 1079: spl( s ); ! 1080: } ! 1081: ! 1082: /* ! 1083: * Send a command byte to the ! 1084: * NEC chip, first waiting until the chip ! 1085: * says that it is ready. No timeout is ! 1086: * performed; if the chip dies, we do too! ! 1087: */ ! 1088: ! 1089: static ! 1090: flput( b ) ! 1091: ! 1092: int b; ! 1093: ! 1094: { ! 1095: register int i = 0; ! 1096: ! 1097: while ( (inb(FDCMSR) & (MSRRQM|MSRDIO)) != MSRRQM ) { ! 1098: if ( --i == 0 ) { ! 1099: printf("flput: timeout\n"); ! 1100: return; ! 1101: } ! 1102: } ! 1103: ! 1104: outb(FDCDAT, b); ! 1105: } ! 1106: ! 1107: /* ! 1108: * Dissassemble the floppy error status for user reference. ! 1109: */ ! 1110: ! 1111: static ! 1112: flstatus() ! 1113: { ! 1114: printf("fd%d: head=%u cyl=%u", ! 1115: fl.fl_cmdstat[0] & 3, ! 1116: fl.fl_head, fl.fl_fcyl ); ! 1117: ! 1118: /* ! 1119: * Report on ST0 bits. ! 1120: */ ! 1121: if ( fl.fl_ncmdstat >= 1 ) { ! 1122: if ( fl.fl_cmdstat[0] & ST0_NR ) ! 1123: printf(" <Not Ready>"); ! 1124: ! 1125: if ( fl.fl_cmdstat[0] & ST0_EC ) ! 1126: printf(" <Equipment Check>"); ! 1127: } ! 1128: ! 1129: /* ! 1130: * Report on ST1 bits. ! 1131: */ ! 1132: if ( fl.fl_ncmdstat >= 2 ) { ! 1133: if ( fl.fl_cmdstat[1] & ST1_MA ) ! 1134: printf(" <Missing Address Mark>"); ! 1135: ! 1136: if ( fl.fl_cmdstat[1] & ST1_NW ) ! 1137: printf(" <Write Protected>"); ! 1138: ! 1139: if ( fl.fl_cmdstat[1] & ST1_ND ) ! 1140: printf(" <No Data>"); ! 1141: ! 1142: if ( fl.fl_cmdstat[1] & ST1_OR ) ! 1143: printf(" <Overrun>"); ! 1144: ! 1145: if ( fl.fl_cmdstat[1] & ST1_DE ) ! 1146: printf(" <Data Error>"); ! 1147: ! 1148: if ( fl.fl_cmdstat[1] & ST1_EN ) ! 1149: printf(" <End of Cyl>"); ! 1150: } ! 1151: ! 1152: /* ! 1153: * Report on ST2 bits. ! 1154: */ ! 1155: if ( fl.fl_ncmdstat >= 3 ) { ! 1156: if ( fl.fl_cmdstat[2] & ST2_MD ) ! 1157: printf(" <Missing Data Address Mark>"); ! 1158: ! 1159: if ( fl.fl_cmdstat[2] & ST2_BC ) ! 1160: printf(" <Bad Cylinder>"); ! 1161: ! 1162: if ( fl.fl_cmdstat[2] & ST2_WC ) ! 1163: printf(" <Wrong Cylinder>"); ! 1164: ! 1165: if ( fl.fl_cmdstat[2] & ST2_DD ) ! 1166: printf(" <Bad Data CRC>"); ! 1167: ! 1168: if ( fl.fl_cmdstat[2] & ST2_CM ) ! 1169: printf(" <Data Deleted>"); ! 1170: } ! 1171: ! 1172: printf("\n"); ! 1173: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.