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