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