|
|
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.