|
|
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: #include <sys/abios.h>
33: static short intimeout;
34: static request_block_fl fl_rb;
35:
36: void floppy_function();
37: void floppy_functionb();
38: static void fl_drive_off();
39:
40: /*
41: * Patchable parameters (default to IBM PC/XT values).
42: */
43:
44: int fl_srt = 0xC; /* Floppy seek step rate, in unit 2 millisec */
45: /* NOT DIRECTLY ENCODED */
46: /* COMPAQ wants 0xD */
47: int fl_hlt = 1; /* Floppy head load time, in unit 4 millisec */
48: int fl_hut = 0xF; /* Floppy head unload time, in unit 32 millisec */
49:
50: int flload();
51: int flunload();
52: void flreset();
53: int flopen();
54: int flblock();
55: int flread();
56: int flwrite();
57: int flioctl();
58: static void flstart();
59: static void flintr();
60: static void fldone();
61: static void fltimer();
62: int nulldev();
63: int nonedev();
64:
65: CON flcon = {
66: DFBLK|DFCHR, /* Flags */
67: FL_MAJOR, /* Major index */
68: flopen, /* Open */
69: nulldev, /* Close */
70: flblock, /* Block */
71: flread, /* Read */
72: flwrite, /* Write */
73: flioctl, /* Ioctl */
74: nulldev, /* Powerfail */
75: fltimer, /* Timeout */
76: flload, /* Load */
77: flunload /* Unload */
78: };
79:
80: /*
81: * Driver States.
82: */
83: #ifdef OLD
84: #define SIDLE 0 /* Idle */
85: #define SSEEK 1 /* Need seek */
86: #define SRDWR 2 /* Need read/write command */
87: #define SENDIO 3 /* Need end I/O processing */
88: #define SDELAY 4 /* Delay before next disk operation */
89: #define SHDLY 5 /* Head settling delay before r/w */
90: #define SRESET 6 /* Doing a reset */
91: #else
92: #define SIDLE 0 /* controller idle */
93: #define SRETRY 1 /* seeking */
94: #define SREAD 2 /* reading */
95: #define SWRITE 3 /* writing */
96: #define SRESET 4 /* reseting */
97:
98: extern char *smsg[];
99: #endif
100:
101: #define funit(x) (minor(x)>>4) /* Unit/drive number */
102: #define fkind(x) (0x7) /* Kind of format */
103: /* #define fkind(x) (minor(x)&0x7) Kind of format */
104: #define fhbyh(x) (minor(x)&0x8) /* 0=Side by side, 1=Head by head */
105:
106: static
107: struct fdata {
108: int fd_size; /* Blocks per diskette */
109: int fd_nhds; /* Heads per drive */
110: int fd_trks; /* Tracks per side */
111: int fd_offs; /* Sector base */
112: int fd_nspt; /* Sectors per track */
113: char fd_GPL[4]; /* Controller gap param (indexed by rate) */
114: char fd_N; /* Controller size param */
115: char fd_FGPL; /* Format gap length */
116: } fdata[] = {
117: /* 8 sectors per track, surface by surface seek. */
118: { 320,1,40,0, 8, { 0x00,0x23,0x2A }, 2,0x50 }, /* Single sided */
119: { 640,2,40,0, 8, { 0x00,0x23,0x2A }, 2,0x50 }, /* Double sided */
120: { 1280,2,80,0, 8, { 0x00,0x23,0x2A }, 2,0x50 }, /* Quad density */
121: /* 9 sectors per track, surface by surface seek. */
122: { 360,1,40,0, 9, { 0x00,0x23,0x2A }, 2,0x50 }, /* Single sided */
123: { 720,2,40,0, 9, { 0x00,0x23,0x2A }, 2,0x50 }, /* Double sided */
124: { 1440,2,80,0, 9, { 0x00,0x23,0x2A }, 2,0x50 }, /* Quad density */
125: /* 15 sectors per track, surface by surface seek. */
126: { 2400,2,80,0,15, { 0x1B,0x00,0x00 }, 2,0x54 }, /* High capacity */
127: /* 18 sectors per track, surface by surface seek. */
128: { 2880,2,80,0,18, { 0x1B,0x00,0x00 }, 2,0x54 } /* 1.44 3.5" */
129: };
130:
131:
132: static
133: struct fl {
134: BUF *fl_actf; /* Queue, forward */
135: BUF *fl_actl; /* Queue, backward */
136: paddr_t fl_addr; /* Address */
137: int fl_nsec; /* # of sectors */
138: int fl_secn; /* Current sector */
139: struct fdata fl_fd; /* Disk kind data */
140: int fl_fcyl; /* Floppy cylinder # */
141: char fl_incal[4]; /* Disk in cal flags */
142: char fl_ndsk; /* # of 5 1/4" drives */
143: char fl_unit; /* Unit # */
144: char fl_mask; /* Handy unit mask */
145: char fl_hbyh; /* 0/1 = Side by side/Head by head */
146: char fl_nerr; /* Error count */
147: int fl_ncmdstat; /* Number of cmd status bytes recvd */
148: char fl_cmdstat[8]; /* Command Status buffer */
149: int fl_nintstat; /* Number of intr status bytes recvd */
150: char fl_intstat[4]; /* Interrupt Status buffer */
151: int fl_fsec; /* Floppy sector # */
152: int fl_head; /* Floppy head */
153: char fl_init; /* FDC init done flag */
154: char fl_state; /* Processing state */
155: char fl_mstatus; /* Motor status */
156: char fl_time[4]; /* Motor timeout */
157: char fl_rate; /* Data rate: 500,300,250,?? kbps */
158: char fl_type[4]; /* Type of drive: 2 = HiCap */
159: int fl_wflag; /* Write operation */
160: int fl_recov; /* Recovery initiated */
161: } fl;
162:
163: static BUF flbuf;
164: static TIM fltim;
165: static TIM flrstlck;
166:
167: /*
168: * The load routine asks the
169: * switches how many drives are present
170: * in the machine, and sets up the field
171: * in the floppy database. It also grabs
172: * the level 6 interrupt vector.
173: */
174: static
175: flload()
176: {
177: register int eflag;
178: register int s = 0;
179:
180: printf("loading fl\n");
181: init_abios();
182:
183: /*
184: * Read floppy equipment byte from CMOS ram
185: * drive 0 is in high nibble, drive 1 is in low nibble.
186: */
187: outb( 0x70, 0x10 );
188: /* delay */
189: eflag = inb( 0x71 );
190:
191: /*
192: * Flag hardware as an IBM AT if neither equipment byte nibble is
193: * greater than 4 (since 5 through 15 are reserved nibble values - see
194: * IBM AT Technical Reference manual, page 1-50). Note that this
195: * relies on the fact that in the XT, this byte will "float" high.
196: * NOTE: 1.44 Mbyte 3.5 inch drives are type 4
197: */
198: if ( (eflag & 0x88) == 0 ) {
199:
200: /*
201: * Reinitialize patchable parameters for IBM AT.
202: */
203: fl_srt = 0xD; /* Floppy seek step rate, in unit 2 ms */
204: /* NOT DIRECTLY ENCODED */
205: fl_hlt = 25; /* Floppy head load time, in unit 4 ms */
206:
207: /*
208: * Define AT drive information.
209: */
210: fl.fl_type[0] = eflag >> 4;
211: fl.fl_type[1] = eflag & 15;
212: fl.fl_rate = 1; /* Must not be 2 */
213:
214: /*
215: * Determine number of AT floppy drives.
216: */
217: if ( eflag & 0xF0 ) {
218: fl.fl_ndsk++;
219: if ( eflag & 0x0F )
220: fl.fl_ndsk++;
221: }
222: } else {
223: /*
224: * Define XT drive information.
225: */
226: eflag = int11();
227: fl.fl_rate = 2;
228: if ( eflag & 1 )
229: fl.fl_ndsk = ((eflag >> 6) & 0x03) + 1;
230: }
231:
232: fl.fl_actf = NULL; /* Start up with this Null to avoid phony calls */
233:
234: if ( fl.fl_ndsk ) {
235:
236: s = sphi();
237: setivec(6, &flintr);
238: spl( s );
239:
240: fl_rb.length = 0x51;
241: fl_rb.logical_id = 3;
242: fl_rb.unit = 0;
243: fl_rb.function = 3;
244: fl_rb.reserved = 0L;
245: fl_rb.ret_code = 0xffff;
246: d1_func(&fl_rb, START_P);
247: if (fl_rb.ret_code)
248: printf("\nfloppy function 3 returned = %d\n",
249: fl_rb.ret_code);
250: flreset();
251: }
252: }
253:
254: /*
255: * Release resources.
256: */
257: flunload()
258: {
259: printf("doing an flunload\n");
260: /*
261: * Clear interrupt vector.
262: */
263: if ( fl.fl_ndsk )
264: clrivec(6);
265:
266: /*
267: * Cancel timed function.
268: */
269: timeout( &fltim, 0, NULL, NULL );
270:
271: /*
272: * Cancel periodic [1 second] invocation.
273: */
274: drvl[FL_MAJOR].d_time = 0;
275:
276: /*
277: * Turn motors off.
278: */
279: /* outb(FDCDOR, DORNMR | DORIEN );*/
280: }
281:
282:
283: /**
284: * void
285: * flreset() -- reset floppy disk controller.
286: */
287: static void
288: flreset()
289: {
290: register int s;
291:
292: fl.fl_state = SRESET;
293: fl_rb.length = 0x51;
294: fl_rb.logical_id = 3;
295: fl_rb.unit = 0;
296: fl_rb.function = 5;
297: fl_rb.reserved = 0L;
298: fl_rb.ret_code = 0xffff;
299: fl_rb.vars.f5.reserved = 0;
300: floppy_function(START_P);
301:
302: /* printf("before reset\n"); */
303: {int i; for (i=0;i<1000; i++);}
304: s = sphi();
305: while ((fl_rb.ret_code == 1) || (fl_rb.ret_code == 2))
306: sleep(&flrstlck, CVWAIT, IVWAIT, SVWAIT);
307: spl( s );
308: {int i; for (i=0;i<1000; i++);}
309: /* printf("after reset\n"); */
310:
311: fl.fl_state = SIDLE;
312: if (fl_rb.ret_code != 0)
313: printf("FL: reset failed - %u\n", fl_rb.ret_code);
314: return;
315: }
316:
317:
318: /*
319: * The open routine screens out
320: * opens of illegal minor devices and
321: * performs the NEC specify command if
322: * this is the very first floppy disk
323: * open call.
324: */
325:
326: static
327: flopen( dev, mode )
328: dev_t dev;
329: int mode;
330:
331: {
332: /*
333: * Validate existence and data rate [Gap length != 0].
334: */
335: if ( funit(dev) >= fl.fl_ndsk )
336: {
337: u.u_error = ENXIO;
338: return;
339: }
340: }
341:
342: /*
343: * The read routine just calls
344: * off to the common raw I/O processing
345: * code, using a static buffer header in
346: * the driver.
347: */
348:
349: static
350: flread( dev, iop )
351: dev_t dev;
352: IO *iop;
353: {
354: ioreq(&flbuf, iop, dev, BREAD);
355: }
356:
357: /*
358: * The write routine is just like the
359: * read routine, except that the function code
360: * is write instead of read.
361: */
362:
363: static
364: flwrite( dev, iop )
365:
366: dev_t dev;
367: IO *iop;
368:
369: {
370: ioreq(&flbuf, iop, dev, BWRITE);
371: }
372:
373: /*
374: * The ioctl routine simply queues a format request
375: * using flbuf.
376: * The only valid command is to format a track.
377: * The parameter block contains the header records supplied to the controller.
378: */
379:
380: static
381: flioctl( dev, com, par )
382:
383: dev_t dev;
384: int com;
385: char *par;
386:
387: {
388: register unsigned s;
389: register struct fdata *fdp;
390: unsigned hd, cyl;
391:
392: /* {int i; for (i=0;i<1000; i++);} */
393: /* printf("fl in fioctl\n"); */
394: if (com != FDFORMAT) {
395: u.u_error = EINVAL;
396: return;
397: }
398:
399: printf("No format allowed yet.\n");
400: /* These is an ABIOS command to format. For now, just error out */
401: u.u_error = EINVAL;
402: return;
403:
404: fdp = &fdata[ fkind(dev) ];
405: cyl = getubd(par);
406: hd = getubd(par+1);
407:
408: if (hd > 1 || cyl >= fdp->fd_trks) {
409: u.u_error = EINVAL;
410: return;
411: }
412:
413: /*
414: * The following may need some explanation.
415: * dmareq will:
416: * claim the buffer,
417: * bounds check the parameter buffer,
418: * lock the parameter buffer in memory,
419: * convert io_seek to b_bno,
420: * dispatch the request,
421: * wait for completion,
422: * and unlock the parameter buffer.
423: * The b_bno is reconverted to hd, cyl in flfsm.
424: */
425:
426: s = fhbyh(dev) ? (cyl * fdp->fd_nhds + hd) : (hd * fdp->fd_trks + cyl);
427: s *= fdp->fd_nspt;
428: u.u_io.io_seek = ((long)s) * BSIZE;
429: #ifdef _I386
430: u.u_io.io.vbase = par;
431: #else
432: u.u_io.io_base = par;
433: #endif
434: u.u_io.io_ioc = fdp->fd_nspt * 4;
435: dmareq(&flbuf, &u.u_io, dev, FDFORMAT);
436: }
437:
438: /*
439: * Start up block I/O on a
440: * buffer. Check that the block number
441: * is not out of range, given the style of
442: * the disk. Put the buffer header into the
443: * device queue. Start up the disk if the
444: * device is idle.
445: */
446:
447: static
448: flblock( bp )
449:
450: register BUF *bp;
451: {
452: register unsigned bno;
453:
454: intimeout = 0;
455:
456: bno = bp->b_bno + (bp->b_count >> 9) - 1;
457: if ((unsigned)bp->b_bno > fdata[ fkind(bp->b_dev) ].fd_size) {
458: bp->b_flag |= BFERR;
459: bdone(bp);
460: return;
461: }
462:
463: if (bp->b_req != FDFORMAT && bno>=fdata[ fkind(bp->b_dev) ].fd_size) {
464: bp->b_resid = bp->b_count;
465: if (bp->b_flag & BFRAW)
466: bp->b_flag |= BFERR;
467: bdone(bp); /* return w/ b_resid != 0 */
468: return;
469: }
470:
471: if ((bp->b_count&0x1FF) != 0) {
472: if (bp->b_req != FDFORMAT) {
473: bp->b_flag |= BFERR;
474: bdone(bp);
475: return;
476: }
477: }
478:
479: /* bp->b_actf = NULL; */
480:
481: if (fl.fl_actf == NULL)
482: fl.fl_actf = bp;
483: else
484: fl.fl_actl->b_actf = bp;
485:
486: fl.fl_actl = bp;
487:
488:
489: if (fl.fl_state == SRESET)
490: printf("fl.fl_state (%d) != SIDLE (%d)\n", fl.fl_state,SIDLE);
491:
492: if (fl.fl_state == SIDLE)
493: {
494: drvl[FL_MAJOR].d_time = 0;
495: if (fldequeue())
496: flstart();
497: }
498:
499: }
500:
501: /**
502: *
503: * int
504: * fldequeue() - obtain next disk read/write operation
505: *
506: * Action: Pull some work from the disk queue.
507: *
508: * Return: 0 = no work.
509: * * = work to do.
510: */
511: static int
512: fldequeue()
513: {
514: register BUF * bp = fl.fl_actf;
515: register struct fdata *dp;
516:
517: if (bp == NULL)
518: return (0);
519:
520: dp = &fdata[fkind(bp->b_dev)];
521: fl.fl_secn = (bp->b_bno % dp->fd_nspt) + 1;
522: fl.fl_head = bp->b_bno / dp->fd_nspt;
523: fl.fl_fcyl = fl.fl_head / dp->fd_nhds;
524: fl.fl_head = fl.fl_head % dp->fd_nhds;
525:
526: fl.fl_nsec = bp->b_count / BSIZE;
527:
528: if (bp->b_faddr == 0L)
529: {
530: printf("FL: called with a null address for b_faddr, bno=%d\n"
531: ,bp->b_bno);
532: fl.fl_actf = bp->b_actf;
533: return 0;
534: }
535: else
536: fl.fl_addr = vtop(bp->b_faddr);
537:
538: return (1);
539: }
540:
541:
542: /**
543: *
544: * void
545: * flstart() - start or restart next disk read/write operation.
546: *
547: * Action: Initiate disk read/write operation.
548: **/
549: static void
550: flstart()
551: {
552: fl_rb.length = 0x51;
553: fl_rb.logical_id = 3;
554: fl_rb.unit = 0;
555: fl_rb.reserved = 0L;
556: fl_rb.ret_code = 0xffff;
557:
558: /* Note that the items below are set up the same way for a
559: * read or a write. */
560: fl_rb.vars.f8.reserved = 0;
561: fl_rb.vars.f8.reserved1 = 0L;
562: fl_rb.vars.f8.dptr = fl.fl_addr;
563: fl_rb.vars.f8.reserved2 = 0;
564: fl_rb.vars.f8.cylinder = fl.fl_fcyl;
565: fl_rb.vars.f8.head = fl.fl_head;
566: fl_rb.vars.f8.sector = fl.fl_secn;
567: fl_rb.vars.f8.sectors_read = fl.fl_nsec;
568:
569: if (fl.fl_actf->b_req == BWRITE) {
570: fl_rb.function = 9;
571: fl.fl_state = SWRITE;
572: }
573: else {
574: fl_rb.function = 8;
575: fl.fl_state = SREAD;
576: }
577: floppy_function(START_P);
578: }
579:
580: /**
581: *
582: * void
583: * flintr() - Interrupt routine.
584: *
585: */
586: static void
587: flintr()
588: {
589: d1_func(&fl_rb, INTERRUPT_P);
590: /* printf("return val (int) = %x\n", fl_rb.ret_code); */
591: defer(floppy_functionb, INTERRUPT_P);
592: }
593:
594: /**
595: *
596: * int
597: * flerror()
598: *
599: * Action: Check for drive error.
600: * If found, increment error count and report it.
601: *
602: * Return: 0 = No error found.
603: * 1 = Error occurred.
604: */
605: static int
606: flerror()
607: {
608: register BUF * bp = fl.fl_actf;
609:
610: if (fl_rb.ret_code <= 2)
611: return 0; /* For now, do nothing */
612: else
613: {
614: #if 0
615: printf("fl%d%c: bno=%U head=%u cyl=%u error=%x",
616: fl.fl_drv,
617: (bp->b_dev & SDEV) ? 'x' : fl.fl_partn % NPARTN + 'a',
618: (bp->b_count/BSIZE) + bp->b_bno
619: + fl.fl_caching - fl.fl_nsec,
620: fl.fl_head, fl.fl_fcyl, fl_rb.ret_code);
621: #endif
622: return fl_rb.ret_code;
623: }
624: }
625:
626: /**
627: *
628: * void
629: * flrecov()
630: *
631: * Action: Attempt recovery.
632: */
633: static void
634: flrecov()
635: {
636: register BUF *bp = fl.fl_actf;
637:
638: switch (fl_rb.ret_code) {
639:
640: case 0x8006: /* Media changed - retry */
641: switch(fl.fl_state)
642: {
643: case SREAD:
644: case SWRITE:
645: flreset();
646: fldequeue();
647: flstart();
648: break;
649: default:
650: break;
651: }
652: break;
653: default: /* Anything else - Give up on block */
654: printf("FL: error %x in %s.\n", fl_rb.ret_code,
655: smsg[fl.fl_state]);
656:
657: bp->b_flag |= BFERR;
658: fldone();
659: }
660: }
661:
662: /**
663: *
664: * void
665: * fldone()
666: *
667: * Action: Release current i/o buffer to the O/S.
668: */
669: static void
670: fldone()
671: {
672: register BUF * bp = fl.fl_actf;
673:
674: drvl[FL_MAJOR].d_time = 0;
675: fl.fl_state = SIDLE;
676: bdone(bp);
677:
678: if (bp != NULL)
679: fl.fl_actf = bp->b_actf;
680: else
681: fl.fl_actf = NULL;
682:
683: if (fldequeue())
684: flstart();
685: else if (intimeout == 0) {
686: intimeout = 1; /* Set up to turn off the drive */
687: drvl[FL_MAJOR].d_time = 5;
688: }
689: }
690:
691:
692:
693: void floppy_function(type)
694: int type;
695: {
696: d1_func(&fl_rb, type);
697: /* printf("FL: return val = %x\n", fl_rb.ret_code); */
698: {int i; for (i=0;i<1000; i++);}
699: floppy_functionb();
700: }
701:
702: void floppy_functionb()
703: {
704: static int test=0;
705: while (fl_rb.ret_code == 2) /* Wait for time */
706: {
707: test++;
708: if (test > 1) printf("@");
709: {
710: long i;
711: for(i=0L; i < fl_rb.vars.f8.wait_time; i+=16)
712: ;
713: }
714: /*
715: timeout(&fltim, 1, wakeup, (int)&fltim);
716: sleep((char *)&fltim, CVTTOUT, IVTTOUT, SVTTOUT);
717: */
718:
719: d1_func(&fl_rb, INTERRUPT_P);
720: }
721: test=0;
722: if (fl_rb.ret_code == 0) /* Finished */
723: {
724: if (fl.fl_state != SRESET)
725: {
726: fl.fl_actf->b_resid = 0;
727: fldone();
728: }
729: else
730: wakeup(&flrstlck);
731: }
732: else if (fl_rb.ret_code == 1) /* Wait for int */
733: {
734: /*fl.fl_state = SINT; */
735: /*printf("Floppy driver is waiting for an interrupt\n"); */
736: }
737: else
738: {
739: printf("bp->b_bno=%ld, fl.fl_secn=%d, fl.fl_fcyl=%d, fl.fl_h"
740: "ead=%d, fl.fl_nsec=%d\n", fl.fl_actf->b_bno,
741: fl.fl_secn, fl.fl_fcyl, fl.fl_head, fl.fl_nsec);
742: flrecov();
743: }
744: }
745:
746: /**
747: *
748: * void
749: * fltimer() - wait for timeout
750: *
751: * Action: If drvl[FL_MAJOR] is greater than zero, decrement it.
752: * If it decrements to zero, call the abios again
753: * or turn off the disktimer it timeout = 1;
754: */
755: static void
756: fltimer()
757: {
758: register int s;
759:
760: s = sphi();
761: if (--drvl[FL_MAJOR].d_time > 0) {
762: spl(s);
763: return;
764: }
765: if (intimeout) {
766: intimeout = 2;
767: defer(fl_drive_off,0);
768: }
769: else
770: floppy_function(INTERRUPT_P);
771: spl(s);
772: }
773:
774:
775: static void
776: fl_drive_off()
777: {
778: fl_rb.logical_id = 3;
779: fl_rb.unit = 0;
780: fl_rb.function = 0xf;
781: fl_rb.reserved = 0L;
782: fl_rb.ret_code = 0xffff;
783: fl_rb.vars.ff.reserved = 0;
784: d1_func(&fl_rb, START_P);
785: if (fl_rb.ret_code)
786: printf("\nfloppy function 0xf returned = %d\n",
787: fl_rb.ret_code);
788: intimeout = 0; /* Drive is now turned off */
789:
790: return;
791: }
792:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.