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