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