|
|
1.1 root 1: /*-
2: * Copyright (c) 1990 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Don Ahn.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)fd.c 7.4 (Berkeley) 5/25/91
37: */
38:
39: #include "fd.h"
40: #if NFD > 0
41:
42: #include "param.h"
43: #include "dkbad.h"
44: #include "systm.h"
45: #include "conf.h"
46: #include "file.h"
47: #include "ioctl.h"
48: #include "buf.h"
49: #include "uio.h"
50: #include "i386/isa/isa_device.h"
51: #include "i386/isa/fdreg.h"
52: #include "i386/isa/icu.h"
1.1.1.2 ! root 53: #undef NFD
! 54: #define NFD 2
! 55: /*#define FDDEBUG
! 56: #define FDTEST
! 57: #define FDOTHER*/
1.1 root 58:
1.1.1.2 ! root 59: #define FDUNIT(s) ((s>>3)&1)
! 60: #define FDTYPE(s) ((s)&7)
1.1 root 61:
62: #define b_cylin b_resid
63: #define b_step b_resid
64: #define FDBLK 512
65: #define NUMTYPES 4
66:
67: struct fd_type {
68: int sectrac; /* sectors per track */
69: int secsize; /* size code for sectors */
70: int datalen; /* data len when secsize = 0 */
71: int gap; /* gap len between sectors */
72: int tracks; /* total num of tracks */
73: int size; /* size of disk in sectors */
74: int steptrac; /* steps per cylinder */
75: int trans; /* transfer speed code */
76: };
77:
78: struct fd_type fd_types[NUMTYPES] = {
79: { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */
80: { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */
81: { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */
82: { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */
83: };
84:
85: struct fd_u {
86: int type; /* Drive type (HD, DD */
87: int active; /* Drive activity boolean */
88: int motor; /* Motor on flag */
89: struct buf head; /* Head of buf chain */
90: struct buf rhead; /* Raw head of buf chain */
91: int reset;
92: } fd_unit[NFD];
93:
94:
95: extern int hz;
96:
97: /* state needed for current transfer */
98: static fdc; /* floppy disk controller io base register */
99: int fd_dmachan = 2;
100: static int fd_skip;
101: static int fd_state;
102: static int fd_retry;
103: static int fd_drive;
104: static int fd_track = -1;
105: static int fd_status[7];
106:
107: /*
108: make sure bounce buffer for DMA is aligned since the DMA chip
109: doesn't roll over properly over a 64k boundary
110: */
111: extern struct buf *dma_bounce[];
112:
113: /****************************************************************************/
114: /* autoconfiguration stuff */
115: /****************************************************************************/
116: int fdprobe(), fdattach(), fd_turnoff();
117:
118: struct isa_driver fddriver = {
119: fdprobe, fdattach, "fd",
120: };
121:
122: fdprobe(dev)
123: struct isa_device *dev;
124: {
125: return 1;
126: }
127:
128: fdattach(dev)
129: struct isa_device *dev;
130: { int s;
131:
132: fdc = dev->id_iobase;
133: /* Set transfer to 500kbps */
134: outb(fdc+fdctl,0);
135: fd_turnoff(0);
136: }
137:
138: int
139: fdsize(dev)
140: dev_t dev;
141: {
142: return(2400);
143: }
144:
145: /****************************************************************************/
146: /* fdstrategy */
147: /****************************************************************************/
148: fdstrategy(bp)
149: register struct buf *bp; /* IO operation to perform */
150: {
151: register struct buf *dp,*dp0,*dp1;
152: long nblocks,blknum;
153: int unit, type, s;
154:
155: unit = FDUNIT(minor(bp->b_dev));
156: type = FDTYPE(minor(bp->b_dev));
157:
158: #ifdef FDTEST
159: printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|",
160: unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr);
161: #endif
162: if ((unit >= NFD) || (bp->b_blkno < 0)) {
163: printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n",
164: unit, bp->b_blkno, bp->b_bcount);
165: pg("fd:error in fdstrategy");
166: bp->b_error = EINVAL;
167: bp->b_flags |= B_ERROR;
168: goto bad;
169: }
170: /*
171: * Set up block calculations.
172: */
173: blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
174: nblocks = fd_types[type].size;
175: if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
176: if (blknum == nblocks) {
177: bp->b_resid = bp->b_bcount;
178: } else {
179: bp->b_error = ENOSPC;
180: bp->b_flags |= B_ERROR;
181: }
182: goto bad;
183: }
184: bp->b_cylin = blknum / (fd_types[type].sectrac * 2);
185: dp = &fd_unit[unit].head;
186: dp0 = &fd_unit[0].head;
187: dp1 = &fd_unit[1].head;
188: dp->b_step = (fd_types[fd_unit[unit].type].steptrac);
189: s = splbio();
190: disksort(dp, bp);
191: if ((dp0->b_active == 0)&&(dp1->b_active == 0)) {
192: #ifdef FDDEBUG
193: printf("T|");
194: #endif
195: dp->b_active = 1;
196: fd_drive = unit;
197: fd_track = -1; /* force seek on first xfer */
198: untimeout(fd_turnoff,unit);
199: fdstart(unit); /* start drive if idle */
200: }
201: splx(s);
202: return;
203:
204: bad:
205: biodone(bp);
206: }
207:
208: /****************************************************************************/
209: /* motor control stuff */
210: /****************************************************************************/
211: set_motor(unit,reset)
212: int unit,reset;
213: {
214: int m0,m1;
215: m0 = fd_unit[0].motor;
216: m1 = fd_unit[1].motor;
217: outb(fdc+fdout,unit | (reset ? 0 : 0xC) | (m0 ? 16 : 0) | (m1 ? 32 : 0));
218: }
219:
220: fd_turnoff(unit)
221: int unit;
222: {
223: fd_unit[unit].motor = 0;
224: if (unit) set_motor(0,0);
225: else set_motor(1,0);
226: }
227:
228: fd_turnon(unit)
229: int unit;
230: {
231: fd_unit[unit].motor = 1;
232: set_motor(unit,0);
233: }
234:
235: /****************************************************************************/
236: /* fdc in/out */
237: /****************************************************************************/
238: int
239: in_fdc()
240: {
241: int i;
242: while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM))
243: if (i == NE7_RQM) return -1;
244: return inb(fdc+fddata);
245: }
246:
247: dump_stat()
248: {
249: int i;
250: for(i=0;i<7;i++) {
251: fd_status[i] = in_fdc();
252: if (fd_status[i] < 0) break;
253: }
254: printf("FD bad status :%lx %lx %lx %lx %lx %lx %lx\n",
255: fd_status[0], fd_status[1], fd_status[2], fd_status[3],
256: fd_status[4], fd_status[5], fd_status[6] );
257: }
258:
259: out_fdc(x)
260: int x;
261: {
262: int r,errcnt;
263: static int maxcnt = 0;
264: errcnt = 0;
265: do {
266: r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM));
267: if (r== NE7_RQM) break;
268: if (r==(NE7_DIO|NE7_RQM)) {
269: dump_stat(); /* error: direction. eat up output */
270: #ifdef FDOTHER
271: printf("%lx\n",x);
272: #endif
273: }
274: /* printf("Error r = %d:",r); */
275: errcnt++;
276: } while (1);
277: if (errcnt > maxcnt) {
278: maxcnt = errcnt;
279: #ifdef FDOTHER
280: printf("New MAX = %d\n",maxcnt);
281: #endif
282: }
283: outb(fdc+fddata,x);
284: }
285:
286: /* see if fdc responding */
287: int
288: check_fdc()
289: {
290: int i;
291: for(i=0;i<100;i++) {
292: if (inb(fdc+fdsts)& NE7_RQM) return 0;
293: }
294: return 1;
295: }
296:
297: /****************************************************************************/
298: /* fdopen/fdclose */
299: /****************************************************************************/
300: Fdopen(dev, flags)
301: dev_t dev;
302: int flags;
303: {
304: int unit = FDUNIT(minor(dev));
305: int type = FDTYPE(minor(dev));
306: int s;
307:
308: /* check bounds */
309: if (unit >= NFD) return(ENXIO);
310: if (type >= NUMTYPES) return(ENXIO);
311: /*
312: if (check_fdc()) return(EBUSY);
313: */
314:
315: /* Set proper disk type, only allow one type */
316: return 0;
317: }
318:
319: fdclose(dev, flags)
320: dev_t dev;
321: {
1.1.1.2 ! root 322: return(0);
1.1 root 323: }
324:
325:
326: /****************************************************************************/
327: /* fdstart */
328: /****************************************************************************/
329: fdstart(unit)
330: int unit;
331: {
332: register struct buf *dp,*bp;
333: int s;
334:
335: #ifdef FDTEST
336: printf("st%d|",unit);
337: #endif
338: s = splbio();
339: if (!fd_unit[unit].motor) {
340: fd_turnon(unit);
341: /* Wait for 1 sec */
342: timeout(fdstart,unit,hz);
343: /*DELAY(1000000);*/
344: }else
345: {
346: /* make sure drive is selected as well as on */
347: /*set_motor(unit,0);*/
348:
349: dp = &fd_unit[unit].head;
350: bp = dp->b_actf;
351: fd_retry = 0;
352: if (fd_unit[unit].reset) fd_state = 1;
353: else {
354: /* DO a RESET */
355: fd_unit[unit].reset = 1;
356: fd_state = 5;
357: }
358: fd_skip = 0;
359: #ifdef FDDEBUG
360: printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
361: #endif
362: if (bp->b_cylin != fd_track) {
363: /* Seek necessary, never quite sure where head is at! */
364: out_fdc(15); /* Seek function */
365: out_fdc(unit); /* Drive number */
366: out_fdc(bp->b_cylin * dp->b_step);
367: } else fdintr(0xff);
368: }
369: splx(s);
370: }
371:
372: fd_timeout(x)
373: int x;
374: {
375: int i,j;
376: struct buf *dp,*bp;
377:
378: dp = &fd_unit[fd_drive].head;
379: bp = dp->b_actf;
380:
381: out_fdc(0x4);
382: out_fdc(fd_drive);
383: i = in_fdc();
384: printf("Timeout drive status %lx\n",i);
385:
386: out_fdc(0x8);
387: i = in_fdc();
388: j = in_fdc();
389: printf("ST0 = %lx, PCN = %lx\n",i,j);
390:
391: if (bp) badtrans(dp,bp);
392: }
393:
394: /****************************************************************************/
395: /* fdintr */
396: /****************************************************************************/
397: fdintr(unit)
398: {
399: register struct buf *dp,*bp;
400: struct buf *dpother;
401: int read,head,trac,sec,i,s,sectrac,cyl;
402: unsigned long blknum;
403: struct fd_type *ft;
404:
405: #ifdef FDTEST
406: printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive);
407: #endif
408:
409: dp = &fd_unit[fd_drive].head;
410: bp = dp->b_actf;
411: read = bp->b_flags & B_READ;
412: ft = &fd_types[FDTYPE(bp->b_dev)];
413:
414: switch (fd_state) {
415: case 1 : /* SEEK DONE, START DMA */
416: /* Make sure seek really happened*/
417: if (unit != 0xff) {
418: out_fdc(0x8);
419: i = in_fdc();
420: cyl = in_fdc();
421: if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) {
422: printf("Stray int ST0 = %lx, PCN = %lx:",i,cyl);
423: return;
424: }
425: }
426:
427: fd_track = bp->b_cylin;
428: at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan);
429: blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
430: + fd_skip/FDBLK;
431: sectrac = ft->sectrac;
432: sec = blknum % (sectrac * 2);
433: head = sec / sectrac;
434: sec = sec % sectrac + 1;
435:
436: if (read) out_fdc(0xE6); /* READ */
437: else out_fdc(0xC5); /* WRITE */
438: out_fdc(head << 2 | fd_drive); /* head & unit */
439: out_fdc(fd_track); /* track */
440: out_fdc(head);
441: out_fdc(sec); /* sector XXX +1? */
442: out_fdc(ft->secsize); /* sector size */
443: out_fdc(sectrac); /* sectors/track */
444: out_fdc(ft->gap); /* gap size */
445: out_fdc(ft->datalen); /* data length */
446: fd_state = 2;
447: /* XXX PARANOIA */
448: untimeout(fd_timeout,2);
449: timeout(fd_timeout,2,hz);
450: break;
451: case 2 : /* IO DONE, post-analyze */
452: untimeout(fd_timeout,2);
453: for(i=0;i<7;i++) {
454: fd_status[i] = in_fdc();
455: }
456: if (fd_status[0]&0xF8) {
457: #ifdef FDOTHER
458: printf("status0 err %d:",fd_status[0]);
459: #endif
460: goto retry;
461: }
462: /*
463: if (fd_status[1]){
464: printf("status1 err %d:",fd_status[0]);
465: goto retry;
466: }
467: if (fd_status[2]){
468: printf("status2 err %d:",fd_status[0]);
469: goto retry;
470: }
471: */
472: /* All OK */
473: if (!kernel_space(bp->b_un.b_addr+fd_skip)) {
474: /* RAW transfer */
475: if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr,
476: bp->b_un.b_addr+fd_skip, FDBLK);
477: }
478: fd_skip += FDBLK;
479: if (fd_skip >= bp->b_bcount) {
480: #ifdef FDTEST
481: printf("DONE %d|", bp->b_blkno);
482: #endif
483: /* ALL DONE */
484: fd_skip = 0;
485: bp->b_resid = 0;
486: dp->b_actf = bp->av_forw;
487: biodone(bp);
488: nextstate(dp);
489:
490: } else {
491: #ifdef FDDEBUG
492: printf("next|");
493: #endif
494: /* set up next transfer */
495: blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
496: + fd_skip/FDBLK;
497: fd_state = 1;
498: bp->b_cylin = (blknum / (ft->sectrac * 2));
499: if (bp->b_cylin != fd_track) {
500: #ifdef FDTEST
501: printf("Seek|");
502: #endif
503: /* SEEK Necessary */
504: out_fdc(15); /* Seek function */
505: out_fdc(fd_drive);/* Drive number */
506: out_fdc(bp->b_cylin * dp->b_step);
507: break;
508: } else fdintr(0xff);
509: }
510: break;
511: case 3:
512: #ifdef FDOTHER
513: printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
514: #endif
515: /* Seek necessary */
516: out_fdc(15); /* Seek function */
517: out_fdc(fd_drive);/* Drive number */
518: out_fdc(bp->b_cylin * dp->b_step);
519: fd_state = 1;
520: break;
521: case 4:
522: out_fdc(3); /* specify command */
523: out_fdc(0xDF);
524: out_fdc(2);
525: out_fdc(7); /* Recalibrate Function */
526: out_fdc(fd_drive);
527: fd_state = 3;
528: break;
529: case 5:
530: #ifdef FDOTHER
531: printf("**RESET**\n");
532: #endif
533: /* Try a reset, keep motor on */
534: set_motor(fd_drive,1);
535: set_motor(fd_drive,0);
536: outb(fdc+fdctl,ft->trans);
537: fd_retry++;
538: fd_state = 4;
539: break;
540: default:
541: printf("Unexpected FD int->");
542: out_fdc(0x8);
543: i = in_fdc();
544: sec = in_fdc();
545: printf("ST0 = %lx, PCN = %lx\n",i,sec);
546: out_fdc(0x4A);
547: out_fdc(fd_drive);
548: for(i=0;i<7;i++) {
549: fd_status[i] = in_fdc();
550: }
551: printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
552: fd_status[0], fd_status[1], fd_status[2], fd_status[3],
553: fd_status[4], fd_status[5], fd_status[6] );
554: break;
555: }
556: return;
557: retry:
558: switch(fd_retry) {
559: case 0: case 1:
560: case 2: case 3:
561: break;
562: case 4:
563: fd_retry++;
564: fd_state = 5;
565: fdintr(0xff);
566: return;
567: case 5: case 6: case 7:
568: break;
569: default:
570: printf("FD err %lx %lx %lx %lx %lx %lx %lx\n",
571: fd_status[0], fd_status[1], fd_status[2], fd_status[3],
572: fd_status[4], fd_status[5], fd_status[6] );
573: badtrans(dp,bp);
574: return;
575: }
576: fd_state = 1;
577: fd_retry++;
578: fdintr(0xff);
579: }
580:
581: badtrans(dp,bp)
582: struct buf *dp,*bp;
583: {
584:
585: bp->b_flags |= B_ERROR;
586: bp->b_error = EIO;
587: bp->b_resid = bp->b_bcount - fd_skip;
588: dp->b_actf = bp->av_forw;
589: fd_skip = 0;
590: biodone(bp);
591: nextstate(dp);
592:
593: }
594:
595: /*
596: nextstate : After a transfer is done, continue processing
597: requests on the current drive queue. If empty, go to
598: the other drives queue. If that is empty too, timeout
599: to turn off the current drive in 5 seconds, and go
600: to state 0 (not expecting any interrupts).
601: */
602:
603: nextstate(dp)
604: struct buf *dp;
605: {
606: struct buf *dpother;
607:
608: dpother = &fd_unit[fd_drive ? 0 : 1].head;
609: if (dp->b_actf) fdstart(fd_drive);
610: else if (dpother->b_actf) {
611: #ifdef FDTEST
612: printf("switch|");
613: #endif
614: untimeout(fd_turnoff,fd_drive);
615: timeout(fd_turnoff,fd_drive,5*hz);
616: fd_drive = 1 - fd_drive;
617: dp->b_active = 0;
618: dpother->b_active = 1;
619: fdstart(fd_drive);
620: } else {
621: #ifdef FDTEST
622: printf("off|");
623: #endif
624: untimeout(fd_turnoff,fd_drive);
625: timeout(fd_turnoff,fd_drive,5*hz);
626: fd_state = 0;
627: dp->b_active = 0;
628: }
629: }
630: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.