|
|
1.1 root 1: /*
2: * File: fl386.c
3: *
4: * Purpose: Diskette device control.
5: * Requires 765 controller module fdc.c
6: *
7: * Revised: Wed May 5 11:23:53 1993 CDT
8: */
9:
10: /*
11: * Minor device assignments: xxuuhkkk
12: * uu - unit = 0/1/2/3
13: * kkk - kind, struct fdata infra.
14: * h - alternating head rather than side by side
15: * xx - 0=diskette 1=floppy tape
16: */
17:
18: /*
19: * ----------------------------------------------------------------------
20: * Includes.
21: */
22: #include <sys/coherent.h>
23:
24: #include <errno.h>
25: #include <sys/buf.h>
26: #include <sys/con.h>
27: #include <sys/dmac.h>
28: #include <sys/devices.h>
29: #include <sys/fdc765.h>
30: #include <sys/fdioctl.h>
31: #include <sys/inode.h>
32: #include <sys/sched.h>
33: #include <sys/stat.h>
34:
35: /*
36: * ----------------------------------------------------------------------
37: * Definitions.
38: * Constants.
39: * Macros with argument lists.
40: * Typedefs.
41: * Enums.
42: */
43:
44: #define MAXDRVS 2 /* Maximum number of drives that we will support */
45: #define MAXSCTRS 21 /* Maximum acceptable sectors per track. It is */
46: /* possible to put as many as 10 sectors/track */
47: /* on low density diskettes, 18 sectors/track on */
48: /* 5 1/4" high-density diskettes, and 21 sectors */
49: /* per track on 3 1/2" high density diskettes. */
50: /* the maximum on "2.88" meg diskettes is not */
51: /* known as of this writing, but may be as high */
52: /* as 42. */
53: #define MAXTYPE 4 /* Maximum "type" value as set in the CMOS RAM. */
54: /* The current value of this is 4, the type for */
55: /* 1.44 meg diskettes. */
56:
57: #ifdef FL_XTRA
58: /* This is conditioned out for now due to end-of-volume problems. */
59: #define FL_CYL_2STEP 42
60: #define FL_CYL_HDLO 82
61: #define FL_CYL_HDHI 83
62: #else
63: #define FL_CYL_2STEP 40
64: #define FL_CYL_HDLO 80
65: #define FL_CYL_HDHI 80
66: #endif
67:
68: #define MTIMER 2 /* Motor timeout (seconds) */
69:
70: /*
71: * Driver States.
72: */
73: #define SIDLE 0 /* Idle */
74: #define SSEEK 1 /* Need seek */
75: #define SRDWR 2 /* Need read/write command */
76: #define SENDIO 3 /* Need end I/O processing */
77: #define SDELAY 4 /* Delay before next disk operation */
78: #define SHDLY 5 /* Head settling delay before r/w */
79: #define SLOCK 6 /* Got DMA controller lock */
80: #define SRECAL1 7 /* First recalibrate attempt */
81: #define SRECAL2 8 /* Try seeking to track 2 */
82: #define SRECAL3 9 /* Second recalibrate, if necessary */
83: #define SGOTO2 10 /* After seek to cylinder 2 */
84: #define SRDID 11 /* Get sector ID from FDC */
85: #define SSIDTST 12 /* Testing # of sides */
86:
87: #define funit(x) (minor(x) >> 4) /* Unit/drive number */
88: #define fkind(x) (minor(x) & 0x7) /* Kind of format */
89: #define fhbyh(x) (minor(x) & 0x8) /* 0=Side by side, 1=Head by head */
90:
91: struct FDATA {
92: int fd_size; /* Blocks per diskette */
93: int fd_nhds; /* Heads per drive */
94: int fd_trks; /* Tracks per side */
95: int fd_offs; /* Sector base */
96: int fd_nspt; /* Sectors per track */
97: char fd_GPL[4]; /* Controller gap param (indexed by rate) */
98: char fd_N; /* Controller size param */
99: char fd_FGPL; /* Format gap length */
100: };
101:
102: struct FRATES {
103: char fl_hi_kind; /* "fdata" initial try for hi dens. */
104: char fl_hi_rate; /* -1 here for lo-dens. */
105: char fl_lo_kind; /* Lo-dens "fdata" entry to try 1st.*/
106: char fl_lo_rate; /* Proper lo-density rate for type. */
107: char dflt_kind; /* Default parameters. */
108: char dflt_rate; /* Default data rate. */
109: };
110:
111: #define FL_NUM_DRV_STAT 2
112:
113: struct FL {
114: BUF *fl_actf; /* Queue, forward */
115: BUF *fl_actl; /* Queue, backward */
116: paddr_t fl_addr; /* Address */
117: int fl_nsec; /* # of sectors */
118: int fl_secn; /* Current sector */
119: struct FDATA fl_fd[MAXDRVS]; /* Disk kind data */
120: int fl_fcyl; /* Floppy cylinder # */
121: int fl_2step[MAXDRVS]; /* =1 for double-stepping */
122: char fl_incal[MAXDRVS]; /* Disk in cal flags and current cyl */
123: char fl_dsk_chngd[MAXDRVS]; /* Diskette changed flags */
124: char fl_ndsk; /* # of drives */
125: char fl_unit; /* Current unit # */
126: char fl_selected_unit; /* Last unit selected */
127: char fl_mask; /* Handy unit mask */
128: char fl_hbyh; /* 0/1 = Side by side/Head by head */
129: char fl_nerr; /* Error count */
130: int fl_ndrvstat; /* Number of drv status bytes read */
131: char fl_drvstat[FL_NUM_DRV_STAT]; /* Drive Status buffer */
132: int fl_fsec; /* Floppy sector # */
133: int fl_head; /* Floppy head */
134: char fl_state; /* Processing state */
135: char fl_mstatus; /* Motor status */
136: char fl_time[MAXDRVS]; /* Motor timeout */
137: char fl_rate[MAXDRVS]; /* Data rate: 500,300,250,?? kbps */
138: char fl_type[MAXDRVS]; /* Type of drive: 2 = HiCap */
139: char fl_rate_set; /* Currently set data rate */
140: int fl_wflag; /* Write operation */
141: int fl_recov; /* Recovery initiated */
142: int fl_opct[MAXDRVS]; /* open count for each unit */
143: int fl_we[MAXDRVS]; /* write enable for each unit */
144: };
145:
146: /*
147: * ----------------------------------------------------------------------
148: * Functions.
149: * Import Functions.
150: * Export Functions.
151: * Local Functions.
152: */
153: int nulldev();
154:
155: static int flload();
156: static int flunload();
157: static int flopen();
158: static int flclose();
159: static int flblock();
160: static int flread();
161: static int flwrite();
162: static int flioctl();
163: static int fltimeout();
164:
165: static void flfsm();
166:
167: static void flQhang();
168: static void clrQ();
169: static void fldelay();
170: static void fldone();
171: static int flrate();
172: static void flrecov();
173: static void flIntHandler();
174: static void flDrvSelect();
175: static void flDrvStatus();
176:
177: /*
178: * ----------------------------------------------------------------------
179: * Global Data.
180: * Import Variables.
181: * Export Variables.
182: * Local Variables.
183: */
184:
185: /*
186: * Patchable variables for compatibility with IBM products:
187: *
188: * FL_DSK_CH_PROB - some machines always have the disk changed line turned on.
189: * Currently some PS/1's (Consultant, Professional - possibly most of them)
190: * have this problem, so the default value of zero assumes normal disk change
191: * line operation.
192: *
193: * FL_AUTO_PARM - Only try to autosense floppy parameters if this variable
194: * is nonzero. The PS/2-L40 floppy controller apparently has trouble changing
195: * from low density to high density. Missing address marks when reading
196: * a HD floppy are the symptom if FL_AUTO_PARM is set when it shouldn't be.
197: */
198: int FL_DSK_CH_PROB = 0;
199: int FL_AUTO_PARM = 0;
200:
201: int jopen;
202:
203: /*
204: Here's the problem. We need to be able to tell if the disk has been changed.
205: There is an i/o port we can read, but on some systems, we can get constant
206: false positives. This causes massive floppy slowdown as the disk is constantly
207: recalibrating. The solution is not completely satisfactory, but it's the best
208: one I could come up with. Basically, what I said was since we can't tell when
209: the disk has changed, we will act as if it has changed every time we do an
210: open or a reset. The code
211:
212: if (FL_DSK_CH_PROB)
213: jopen = 2;
214:
215: indicates the need to pretend that the disk has changed. It is set to 2 since
216: there are two parts to the change procedure. Additional code dependent on
217: the value of FL_DSK_CH_PROB says that if we have not just down an open, then
218: we should skip the recal. Otherwise, decrement the counter, and do the
219: recal. - mlk */
220:
221: /* Parameters for each kind of format */
222: struct FDATA fdata[] = {
223: /* 8 sectors per track, surface by surface seek. */
224: { 320,1,40,0, 8, { 0x00,0x20,0x20 }, 2,0x58 }, /* Single sided */
225: { 640,2,40,0, 8, { 0x00,0x20,0x20 }, 2,0x58 }, /* Double sided */
226: { 1280,2,80,0, 8, { 0x00,0x20,0x20 }, 2,0x58 }, /* Quad density */
227: /* 9 sectors per track, surface by surface seek. */
228: { 360,1,40,0, 9, { 0x00,0x20,0x20 }, 2,0x50 }, /* Single sided */
229: { 720,2,40,0, 9, { 0x00,0x20,0x20 }, 2,0x50 }, /* Double sided */
230: { 1440,2,80,0, 9, { 0x00,0x20,0x20 }, 2,0x50 }, /* Quad density */
231: /* 15 sectors per track, surface by surface seek. */
232: { 2400,2,80,0,15, { 0x1B,0x00,0x00 }, 2,0x54 }, /* High capacity */
233: /* 18 sectors per track, surface by surface seek. */
234: { 2880,2,80,0,18, { 0x1B,0x00,0x00 }, 2,0x6C } /* 1.44 3.5" */
235: };
236:
237: /* Parameters for each device type */
238: struct FRATES frates[] = {
239: { 4,-1, 4,-1, 4, FDC_RATE_250K }, /* Type 0 = no drive */
240: { 4,-1, 4, 2, 4, FDC_RATE_250K }, /* Type 1 = 360K */
241: { 6, 0, 4, 1, 6, FDC_RATE_500K }, /* Type 2 = 1.2M */
242: { 4,-1, 5, 2, 5, FDC_RATE_250K }, /* Type 3 = 720K */
243: { 7, 0, 5, 2, 7, FDC_RATE_500K } /* Type 4 = 1.44M */
244: };
245:
246: struct FL fl;
247:
248: /*
249: * We need some areas in global RAM to use as BUF structures
250: * and as data areas for special functions such as formatting,
251: * reading the drive status and reading sector IDs. There is
252: * one set for each drive. When the blocks for a drive are in
253: * use, the "drv_locked" char is set to non-zero, and is
254: * cleared otherwise. While this scheme doesn't provide
255: * complete reentrancy, it does allow both drives to be used
256: * "at once" by separate tasks.
257: */
258: char drv_locked[MAXDRVS]; /* One for each possible drive */
259: char sw3[MAXDRVS];
260: BUF flbuf[MAXDRVS];
261:
262: /*
263: * These next items are related to the floppy disk system
264: * in general, so we only need one of each.
265: */
266: TIM fltim;
267: TIM fldmalck; /* DMA lock deferred function structure. */
268: char fl_clrng_cd;
269: char fl_intlv_ct, /* Counts sectors to find interleave. */
270: fl_get_intlv, /* =1 to start search for interleave. */
271: fl_lk4_id, /* Sector ID to look for for interleave. */
272: fl_alt_kind, /* Alternate disk parameter index and */
273: fl_alt_rate, /* data rate to use if not first value. */
274: fl_1st_ID, /* Detects when all track sectors scanned*/
275: fl_hi_ID; /* Highest sector ID read so far. */
276:
277: /*
278: * Patchable parameters.
279: */
280:
281: int fl_srt = 0xD; /* Floppy seek step rate, in unit -2 millisec */
282: /* F=1ms, E=2ms, etc. */
283: /* All drives HAVE to work at 5 msec/step, so */
284: /* they HAVE to work at 6 msec/step! (The use of */
285: /* 8 msec/step in the old PCs was just IBM being */
286: /* excessively conservative. MS/PC-DOS, starting with */
287: /* version 2.0, changes it to 6 msec/step. There */
288: /* are, in fact, lots of drives that will step at */
289: /* 4 msec/step, but there's no sense in pushing it.) */
290: int fl_hlt = 25; /* Floppy head load time, in unit 4 millisec */
291: int fl_hut = 0xF; /* Floppy head unload time, in unit 32 millisec */
292: int fl_disp = 0; /* If nonzero, print drive parameters on screen */
293:
294: CON fl386con = {
295: DFBLK | DFCHR, /* Flags */
296: FL_MAJOR, /* Major index */
297: flopen, /* Open */
298: flclose, /* Close */
299: flblock, /* Block */
300: flread, /* Read */
301: flwrite, /* Write */
302: flioctl, /* Ioctl */
303: nulldev, /* Powerfail */
304: fltimeout, /* Timeout */
305: flload, /* Load */
306: flunload /* Unload */
307: };
308:
309: static int flOpenCount; /* Number of pending opens for this driver. */
310:
311: /*
312: * ----------------------------------------------------------------------
313: * Code.
314: */
315:
316: /*
317: * The load routine asks the
318: * switches how many drives are present
319: * in the machine, and sets up the field
320: * in the floppy database. It also grabs
321: * the level 6 interrupt vector.
322: */
323: static int
324: flload()
325: {
326: register int eflag;
327: register int s, t;
328:
329: flIntr = flIntHandler;
330: fl_clrng_cd = 0;
331:
332: /*
333: * Read floppy equipment byte from CMOS ram
334: * drive 0 is in high nibble, drive 1 is in low nibble.
335: */
336: eflag = read_cmos(0x10);
337:
338: /*
339: * Define AT drive information.
340: */
341: fl.fl_type[0] = eflag >> 4;
342: fl.fl_type[1] = eflag & 15;
343: fl.fl_ndsk = 0;
344: for (s = 0; s < MAXDRVS; s++) {
345: drv_locked[s] = 0;
346: fl.fl_dsk_chngd[s] = 1;
347: fl.fl_incal[s] = -1;
348: t = fl.fl_type[s];
349: if (t > MAXTYPE) /* --in case we get, like, */
350: fl.fl_type[s] = t = MAXTYPE; /* a 2.88 meg drive. */
351: fl.fl_rate[s] = frates[t].dflt_rate;
352: fl.fl_fd[s] = fdata[frates[t].dflt_kind];
353: if (t) fl.fl_ndsk = s + 1; /* Type 0 = no drive. */
354: }
355:
356: fl.fl_rate_set = 0;
357:
358: if (FL_DSK_CH_PROB)
359: jopen = 1;
360:
361: fl.fl_state = SIDLE;
362:
363: fl.fl_mstatus = 0; /* No motors on */
364: fl.fl_selected_unit = -1; /* No unit selected */
365: }
366:
367: /*
368: * Release resources.
369: */
370: static int
371: flunload()
372: {
373: /*
374: * Cancel timed function.
375: */
376: timeout(&fltim, 0, NULL, NULL);
377:
378: flIntr = NULL;
379: }
380:
381: /*
382: * The open routine screens out
383: * opens of illegal minor devices and
384: * performs the NEC specify command if
385: * this is the very first floppy disk
386: * open call.
387: *
388: * NOTICE: This routine needs to be fixed! There is a problem
389: * if first open is in progress and another first open is tried.
390: * hws - 93/05/18
391: */
392: static int
393: flopen(dev, mode)
394: dev_t dev;
395: int mode;
396: {
397: register int unit_number = funit(dev);
398: register int s;
399:
400: /*
401: * If first open, seize interrupt handler.
402: */
403: if (flOpenCount == 0) {
404: if (!setFlIntr(1)) {
405: devmsg(dev, "FDC busy.");
406: u.u_error = EBUSY;
407: goto worseFlopen;
408: }
409: fdcSpecify(fl_srt, fl_hut, fl_hlt);
410: fdcRate(fl.fl_rate_set);
411: }
412:
413: /*
414: * Validate existence and data rate (Gap length != 0).
415: */
416: if ((unit_number >= fl.fl_ndsk)
417: || (fl.fl_type[unit_number] == 0)
418: || (fdata[fkind(dev)].fd_GPL[flrate(dev)] == 0)) {
419: u.u_error = ENXIO;
420: goto badFlopen; /* status. */
421: }
422:
423: if (FL_DSK_CH_PROB)
424: jopen = 1;
425:
426: /*
427: * May need to write - see if diskette is write proteced.
428: * We do this with a "Sense Drive Status" command. Since
429: * this requires the use of the FDC, we have to schedule it
430: * like data transfer I/O or FORMAT even though it doesn't
431: * use the DMA.
432: */
433: if (fl.fl_opct[unit_number] == 0) { /* first open for this floppy */
434: if (drv_locked[unit_number]) { /* Work areas avail? */
435: u.u_error = EBUSY; /* No. */
436: goto badFlopen; /* status. */
437: } else {
438: drv_locked[unit_number] = 1; /* Grab work areas. */
439: flbuf[unit_number].b_dev = dev;
440: flbuf[unit_number].b_req = BFLSTAT;
441: sw3[unit_number] = 0;
442: /* Get drive status. */
443: flQhang(&flbuf[unit_number]);
444:
445: for (;;) {
446: s = sphi();
447: if (fl.fl_state == SIDLE)
448: flfsm();
449: spl(s);
450: if (sw3[unit_number])
451: break;
452: if (fl.fl_state != SIDLE)
453: x_sleep(&fl.fl_state,
454: pridisk, slpriSigCatch, "flopen");
455:
456: if (nondsig()) { /* signal? */
457: u.u_error = EINTR;
458: drv_locked[unit_number] = 0;
459: goto badFlopen;
460: }
461: }
462:
463: if (flbuf[unit_number].b_resid != 0) {
464: u.u_error = EDATTN; /* Couldn't get drive */
465: drv_locked[unit_number] = 0;
466: goto badFlopen; /* status. */
467: }
468:
469: /* The payoff - set write enable status. */
470: fl.fl_we[unit_number] =
471: ((sw3[unit_number] & ST3_WP)==0);
472: drv_locked[unit_number] = 0; /* Release work areas */
473: }
474:
475: /*
476: * If the drive is low density (no change line) we should
477: * flag the need to verify the disk format and density.
478: * High density drives (which are also dual density) have
479: * change lines that we can check each time we want to read
480: * the drive.
481: */
482: if (frates[fl.fl_type[unit_number]].fl_hi_rate == -1) {
483: fl.fl_incal[unit_number] = -1;
484: fl.fl_dsk_chngd[unit_number] = 1;
485:
486: if (FL_DSK_CH_PROB)
487: jopen = 1;
488: }
489: } /* end of first open stuff */
490:
491: /* If opening for write, volume must be write enabled. */
492: if ((mode & IPW) && !fl.fl_we[unit_number]) {
493: printf("fd%d: <Write Protected>\n", fl.fl_unit);
494: u.u_error = EROFS; /* Diskette write */
495: goto badFlopen; /* protected. */
496: }
497:
498: fl.fl_opct[unit_number]++;
499: flOpenCount++;
500: return;
501:
502: badFlopen:
503: setFlIntr(0);
504: worseFlopen:
505: return;
506: }
507:
508: /*
509: * flclose()
510: */
511: static
512: flclose(dev, mode)
513: dev_t dev;
514: int mode;
515: {
516: register int unit_number = funit(dev);
517:
518: fl.fl_opct[unit_number]--;
519: if (--flOpenCount == 0)
520: setFlIntr(0);
521: }
522:
523: /*
524: * The read routine just calls
525: * off to the common raw I/O processing
526: * code, using a static buffer header in
527: * the driver.
528: */
529: static int
530: flread(dev, iop)
531: dev_t dev;
532: IO *iop;
533: {
534: dmareq(&flbuf[funit(dev)], iop, dev, BREAD);
535: }
536:
537: /*
538: * The write routine is just like the
539: * read routine, except that the function code
540: * is write instead of read.
541: */
542: static int
543: flwrite(dev, iop)
544: dev_t dev;
545: IO *iop;
546: {
547: dmareq(&flbuf[funit(dev)], iop, dev, BWRITE);
548: }
549:
550: /*
551: * The ioctl routine simply queues a format request
552: * using the flbuf for the specified drive.
553: * The only valid command is to format a track.
554: * The parameter block contains the header records supplied to the controller.
555: */
556: static int
557: flioctl(dev, com, par)
558: dev_t dev;
559: int com;
560: char *par;
561: {
562: register unsigned s;
563: register struct fdata *fdp;
564: unsigned hd, cyl;
565:
566: if (com != FDFORMAT) {
567: u.u_error = EINVAL;
568: return;
569: }
570:
571: fdp = &fdata[fkind(dev)]; /* Locate formatting */
572: cyl = getubd(par); /* parameters. */
573: hd = getubd(par+1);
574:
575: if (hd > 1 || cyl >= fdp->fd_trks) {
576: u.u_error = EINVAL;
577: return;
578: }
579:
580: /*
581: * The following may need some explanation.
582: * dmareq will:
583: * claim the buffer,
584: * bounds check the parameter buffer,
585: * lock the parameter buffer in memory,
586: * convert io_seek to b_bno,
587: * dispatch the request,
588: * wait for completion,
589: * and unlock the parameter buffer.
590: * The b_bno is reconverted to hd, cyl in flfsm.
591: */
592:
593: s = fhbyh(dev) ? (cyl * fdp->fd_nhds + hd) : (hd * fdp->fd_trks + cyl);
594: s *= fdp->fd_nspt;
595: u.u_io.io_seek = ((long)s) * BSIZE;
596: u.u_io.io.vbase = par;
597: u.u_io.io_ioc = fdp->fd_nspt * 4;
598: dmareq(&flbuf[funit(dev)], &u.u_io, dev, BFLFMT);
599: return 0;
600: }
601:
602: /*
603: * Start up block I/O on a
604: * buffer. Check that the block number
605: * is not out of range, given the style of
606: * the disk. Put the buffer header into the
607: * device queue. Start up the disk if the
608: * device is idle.
609: */
610: static int
611: flblock(bp)
612: register BUF *bp;
613: {
614: register int s;
615: register unsigned bno;
616:
617: bno = bp->b_bno + (bp->b_count / BSIZE) - 1;
618:
619: { /*DEBUG*/
620: int first = bp->b_bno, last = bno;
621: int fdatasz = fdata[fkind(bp->b_dev)].fd_size;
622: int fl_fdsz = fl.fl_fd[funit(bp->b_dev)].fd_size;
623: /*DEBUG*/
624:
625: if ((bp->b_req == BFLFMT)
626: && ((unsigned)bp->b_bno >= fdata[fkind(bp->b_dev)].fd_size)) {
627: bp->b_flag |= BFERR;
628: bdone(bp);
629: return;
630: }
631:
632: if (bp->b_req != BFLFMT) {
633: if ((unsigned)bp->b_bno >=
634: fl.fl_fd[funit(bp->b_dev)].fd_size) {
635: bp->b_flag |= BFERR;
636: bdone(bp);
637: return;
638: }
639: if (bno >= fl.fl_fd[funit(bp->b_dev)].fd_size) {
640: if (bp->b_flag & BFRAW) {
641: bp->b_flag |= BFERR;
642: }
643: bp->b_resid = bp->b_count;
644: bdone(bp); /* return w/ b_resid != 0 */
645: return;
646: }
647: if ((bp->b_count & 0x1FF) != 0) {
648: bp->b_flag |= BFERR;
649: bdone(bp);
650: return;
651: }
652: }
653: } /*DEBUG*/
654:
655: flQhang(bp); /* Put the block in the queue. */
656:
657: s = sphi();
658: if (fl.fl_state == SIDLE) /* --if necessary, to */
659: flfsm(); /* get things moving. */
660: spl(s);
661: }
662:
663: /******************************************************************/
664:
665: /* Lower-level functions needed by CON entry points. */
666:
667: /*
668: * This routine hangs a BUF in the processing queue
669: */
670: static void
671: flQhang(bp)
672: register BUF *bp;
673: {
674: register int s = sphi(); /* No interrupts during chaining, please */
675:
676: bp->b_actf = NULL;
677:
678: if (fl.fl_actf == NULL)
679: fl.fl_actf = bp;
680: else
681: fl.fl_actl->b_actf = bp;
682:
683: fl.fl_actl = bp;
684:
685: spl(s);
686: }
687:
688: /*
689: * Remove all pending requests for a device from the queue
690: * (used after errors).
691: */
692: static void
693: clrQ(dev)
694: register int dev;
695: {
696: register BUF *bp, *bp2;
697: int s;
698:
699: s = sphi();
700:
701: while ((bp = fl.fl_actf) && (bp->b_dev == dev)) {
702: bp->b_flag |= BFERR; /* Strip BUFs from front */
703: fl.fl_actf = bp->b_actf; /* of queue. */
704: bdone(bp);
705: }
706: while (bp) {
707: fl.fl_actl = bp;
708: if ((bp2 = bp->b_actf) && (bp2->b_dev == dev)) {
709: bp2->b_flag |= BFERR; /* Strip BUFs from rest */
710: bp->b_actf = bp2->b_actf; /* rest of queue. */
711: bdone(bp2);
712: } else
713: bp = bp2;
714: }
715: fl.fl_state = SIDLE;
716: wakeup(&fl.fl_state);
717: spl(s);
718: }
719:
720: /*
721: * This finite state machine is
722: * responsible for all sequencing on the disk.
723: * It builds the commands, does the seeks, spins up
724: * the drive motor for 1 second on the first call,
725: * and so on.
726: * Note that the format command is rather obscurely shoehorned into this.
727: */
728: void
729: flfsm()
730: {
731: register BUF *bp;
732: register int flcmd;
733: register int i;
734: int dods; /* for PS/1, do disk swap */
735:
736: again:
737: bp = fl.fl_actf;
738:
739: switch (fl.fl_state) {
740:
741: case SIDLE:
742: T_HAL(0x40000, printf("SIDLE "));
743: setFlTimer(1);
744:
745: if (bp == NULL) {
746: break;
747: }
748:
749: fl.fl_unit = funit(bp->b_dev);
750: fl.fl_mask = 0x10 << fl.fl_unit;
751:
752: #if 0
753: printf("drv%d: cmd=%d (%s), position=%d, count=%d\n",
754: fl.fl_unit,
755: bp->b_req,
756: (bp->b_req == BREAD) ? "BREAD"
757: : (bp->b_req == BWRITE) ? "BWRITE"
758: : (bp->b_req == BFLSTAT) ? "BFLSTAT"
759: : (bp->b_req == BFLFMT) ? "BFLFMT" : "?????",
760: bp->b_bno,
761: bp->b_count);
762: #endif
763: /*
764: * We do an entire check for drive status here
765: */
766: if (bp->b_req == BFLSTAT) {
767: fl.fl_drvstat[0] = 0;
768: flDrvStatus();
769: sw3[fl.fl_unit] = fl.fl_drvstat[0] | 3;
770: bp->b_resid = (fl.fl_ndrvstat == 1) ? 0 : 1;
771: fl.fl_actf = bp->b_actf;
772: fl.fl_state = SIDLE;
773: goto again;
774: }
775:
776: fl.fl_hbyh = fhbyh(bp->b_dev);
777:
778: fl.fl_addr = bp->b_paddr;
779: fl.fl_secn = bp->b_bno;
780: fl.fl_time[fl.fl_unit] = 0;
781:
782: if ((fl.fl_nsec = bp->b_count>>9) == 0)
783: fl.fl_nsec = 1;
784:
785: fl.fl_nerr = 0;
786:
787: /*
788: * Motor is turned off - turn it on, wait 1 second
789: * (for write operations only)
790: */
791: if (((fl.fl_mstatus & fl.fl_mask) == 0)
792: || (fl.fl_unit != fl.fl_selected_unit)) {
793: flDrvSelect();
794: if ((bp->b_req == BWRITE)
795: || (bp->b_req == BFLFMT)) {
796: timeout(&fltim, HZ, fldelay, SSEEK);
797: fl.fl_state = SDELAY;
798: break;
799: }
800: }
801:
802: /* no break */
803:
804: case SSEEK:
805: T_HAL(0x40000, printf("SSEEK "));
806: flDrvSelect(); /* Keep drive turned on */
807:
808: /*
809: * Test dual-density drive's disk changed line. We must
810: * test now before we (possibly) recalibrate the drive
811: * which would lose us the disk changed indication.
812: */
813:
814: if ((frates[fl.fl_type[fl.fl_unit]].fl_hi_rate != -1)
815: && (inb(FDCCHGL) & DSKCHGD)
816: && (fl_clrng_cd == 0)) {
817: /* See note at def of FL_DSK_CH_PROB above */
818: if (FL_DSK_CH_PROB) {
819: if (jopen) {
820: jopen--;
821: fl.fl_dsk_chngd[fl.fl_unit] = 1;
822: fl.fl_incal[fl.fl_unit] = -1;
823: }
824: } else {
825: fl.fl_dsk_chngd[fl.fl_unit] = 1;
826: fl.fl_incal[fl.fl_unit] = -1;
827: }
828: }
829:
830: fl_clrng_cd = 0;
831:
832: /*
833: * If we have a format command on cylinder zero, head
834: * zero, we must recalibrate the drive first, and set
835: * up the transfer speed and FDC stuff. We ignore
836: * a disk changed condition since the current format
837: * (it may, remember, be unformatted!) is of no
838: * consequence.
839: */
840: if (bp->b_req == BFLFMT) {
841: fl.fl_dsk_chngd[fl.fl_unit] = 0;
842: fl.fl_fd[fl.fl_unit] = fdata[fkind(bp->b_dev)];
843: fl.fl_rate[fl.fl_unit] =
844: fl.fl_rate_set = flrate(bp->b_dev);
845: if ((fl.fl_fd[fl.fl_unit].fd_trks < 45)
846: && (fl.fl_type[fl.fl_unit] != 1))
847: fl.fl_2step[fl.fl_unit] = 1;
848: fdcRate(fl.fl_rate_set);
849: if (fl.fl_secn == 0)
850: fl.fl_incal[fl.fl_unit] = -1;
851: }
852: /*
853: * Drive is not calibrated - seek to track 0.
854: */
855: if (fl.fl_incal[fl.fl_unit] == -1) {
856: fdcRecal(fl.fl_unit);
857: fl.fl_state = SRECAL1;
858: break;
859: } else goto Recalibrated;
860:
861: case SRECAL1:
862: T_HAL(0x40000, printf("SRECAL1 "));
863: /*
864: * If the recalibrate had to step more than 77 cylinders
865: * it will fail. We must check for this condition and
866: * try once more. With some controllers we will also get
867: * an error if the head STARTS over cylinder 0. In either
868: * event we will force a seek to track 2, then recalibrate
869: * again. If this fails, we can't recalibrate the drive.
870: */
871: if ((fdc.fdc_nintstat != 2)
872: || ((fdc.fdc_intstat[0] & (ST0_IC | ST0_SE)) != ST0_SE)) {
873:
874: /* Seek to current drive #, head 0, cylinder 2. */
875: fdcSeek(fl.fl_unit, 0, 2);
876:
877: fl.fl_state = SRECAL2;
878: break;
879: } else goto RecalibrateOK;
880: case SRECAL2:
881: T_HAL(0x40000, printf("SRECAL2 "));
882: fdcRecal(fl.fl_unit);
883: fl.fl_state = SRECAL3;
884: break;
885: case SRECAL3:
886: T_HAL(0x40000, printf("SRECAL3 "));
887: if ((fdc.fdc_nintstat != 2)
888: || ((fdc.fdc_intstat[0] & (ST0_IC | ST0_SE)) != ST0_SE)) {
889: RecalFailed:
890: printf("fd%d: <Can't Recalibrate>\n", fl.fl_unit);
891: clrQ(bp->b_dev);
892: goto again;
893: }
894: RecalibrateOK:
895: /* We now get off of cyl 0 */
896: /* to try to clear the disk */
897: /* changed line, which acts */
898: /* differently on different */
899: /* controllers. <sigh> We */
900: /* use cyl 2 since all for- */
901: /* matted disks will have a */
902: /* track here. */
903:
904: /* Seek to current drive #, head 0, cylinder 2. */
905: fdcSeek(fl.fl_unit, 0, 2);
906:
907: fl.fl_state = SGOTO2;
908: break;
909:
910: case SGOTO2:
911: T_HAL(0x40000, printf("SGOTO2 "));
912: if ((fdc.fdc_nintstat != 2)
913: || ((fdc.fdc_intstat[0] & (ST0_IC | ST0_SE)) != ST0_SE))
914: goto RecalFailed;
915:
916: fl.fl_incal[fl.fl_unit] = 2; /* Heads now on cylinder 2. */
917:
918: Recalibrated:
919: /*
920: * Now, if we don't have to check the interleave factor,
921: * we can continue with the seek!
922: */
923: if (fl.fl_dsk_chngd[fl.fl_unit] == 0) goto RateKnown;
924:
925: /*
926: * <sigh>. Okay, first we'll try the requested density.
927: */
928:
929: /* First we'll make sure */
930: /* we're sitting on cyl 2. */
931: if (fl.fl_incal[fl.fl_unit] != 2) goto RecalibrateOK;
932:
933: /*
934: * We start by trying the requested density:
935: */
936:
937: /* Get requested rate.*/
938: i = fl.fl_rate[fl.fl_unit] = flrate(bp->b_dev);
939: /* This next mess gets*/
940: /* the disk parameters*/
941: /* and the alternate */
942: /* values. */
943: if (i == frates[fl.fl_type[fl.fl_unit]].fl_hi_rate){
944:
945: fl.fl_fd[fl.fl_unit] =
946: fdata[frates[fl.fl_type[fl.fl_unit]].fl_hi_kind];
947: if (FL_AUTO_PARM) {
948: fl_alt_kind =
949: frates[fl.fl_type[fl.fl_unit]].fl_lo_kind;
950: fl_alt_rate =
951: frates[fl.fl_type[fl.fl_unit]].fl_lo_rate;
952: }
953: else {
954: fl_alt_kind =
955: frates[fl.fl_type[fl.fl_unit]].fl_hi_kind;
956: fl_alt_rate =
957: frates[fl.fl_type[fl.fl_unit]].fl_hi_rate;
958: }
959: } else {
960: fl.fl_fd[fl.fl_unit] =
961: fdata[frates[fl.fl_type[fl.fl_unit]].fl_lo_kind];
962: if (FL_AUTO_PARM) {
963: fl_alt_kind =
964: frates[fl.fl_type[fl.fl_unit]].fl_hi_kind;
965: fl_alt_rate =
966: frates[fl.fl_type[fl.fl_unit]].fl_hi_rate;
967: } else {
968: fl_alt_kind =
969: frates[fl.fl_type[fl.fl_unit]].fl_lo_kind;
970: fl_alt_rate =
971: frates[fl.fl_type[fl.fl_unit]].fl_lo_rate;
972: }
973: }
974:
975: fl.fl_state = SRDID; /* Set up to read sector IDs. */
976: fl_get_intlv = 1;
977: fl_intlv_ct =
978: fl_lk4_id =
979: fl_1st_ID =
980: fl_hi_ID = 0;
981:
982: /*
983: * Now we try the rate to see if we can read sector IDs
984: */
985: TryRate:
986: if (fl.fl_rate_set != i) {
987: fl.fl_rate_set = i;
988: fdcRate(fl.fl_rate_set);
989: }
990: GetNextID:
991: fdcPut(CMDRDID);
992: fdcPut(fl.fl_unit); /* Always read side 0. */
993:
994: break; /* Wait for ID to arrive. */
995:
996: case SRDID:
997: T_HAL(0x40000, printf("SRDID "));
998:
999: if ((fdc.fdc_ncmdstat < 7) /* Did we get an ID? */
1000: || ((fdc.fdc_cmdstat[0] & ST0_IC) != ST0_NT) ) {
1001: if (fl_alt_rate == -1) { /* No, is there an alternate?*/
1002: fdcStatus(); /* No, we can't go on. */
1003: clrQ(bp->b_dev);
1004: goto again;
1005: } else {
1006: fl.fl_fd[fl.fl_unit] = fdata[fl_alt_kind];
1007: i = fl.fl_rate[fl.fl_unit] = fl_alt_rate;
1008: fl_alt_rate = -1; /* Flag tried alternate. */
1009: goto TryRate; /* Try alternate density. */
1010: }
1011: }
1012:
1013: /*
1014: * Test interleave
1015: */
1016:
1017: if (fl_get_intlv) /* Looking for interleave? */
1018: if (fl_lk4_id) { /* Yes; started yet? */
1019: if (fl_lk4_id == fdc.fdc_cmdstat[5]) /* Yes. */
1020: fl_get_intlv = 0; /* We have a hit.*/
1021: else /* No hit yet, */
1022: fl_intlv_ct++; /* count sector. */
1023: } else if (fdc.fdc_cmdstat[5] < 5) {/* Can we start yet?*/
1024: fl_intlv_ct = 1; /* Yes; count, */
1025: fl_lk4_id = fdc.fdc_cmdstat[5] + 1;/* set ID */
1026: } /* to find.*/
1027:
1028: /*
1029: * Look for highest ID on track
1030: */
1031:
1032: if (fdc.fdc_cmdstat[5] != fl_1st_ID) {
1033: if (fl_1st_ID == 0)
1034: fl_1st_ID = fdc.fdc_cmdstat[5];
1035: if (fdc.fdc_cmdstat[5] > fl_hi_ID)
1036: fl_hi_ID = fdc.fdc_cmdstat[5];
1037: goto GetNextID;
1038: }
1039:
1040: /*
1041: * Be sure we have the interleave
1042: */
1043:
1044: if (fl_get_intlv) goto GetNextID;
1045:
1046: /*
1047: * So now we know the density and sectors/track
1048: */
1049:
1050: fl.fl_dsk_chngd[fl.fl_unit] = 0;
1051: fl.fl_fd[fl.fl_unit].fd_nspt = fl_hi_ID;
1052:
1053: /*
1054: * There is a problem with the approach used here -
1055: * it assumes that once scan of a track starts, all
1056: * sectors appear in physical order without any misses.
1057: * Unfortunately, this is not always the case, especially
1058: * with 1.44 M 3-1/2" drives.
1059: *
1060: * A workaround which fixes incorrect nspt reading appears
1061: * below.
1062: */
1063: if (fl.fl_fd[fl.fl_unit].fd_nspt > 15
1064: && fl.fl_fd[fl.fl_unit].fd_nspt < 18)
1065: fl.fl_fd[fl.fl_unit].fd_nspt = 18;
1066:
1067: /*
1068: * We're (supposedly) sitting on track 2. We'll
1069: * look at the last sector ID we've read. If it's 1,
1070: * we need to do double-stepping.
1071: */
1072:
1073: if (fl.fl_2step[fl.fl_unit] = (fdc.fdc_cmdstat[3] == 1)) {
1074: fl.fl_fd[fl.fl_unit].fd_trks = FL_CYL_2STEP;
1075: fl.fl_incal[fl.fl_unit] = 1;
1076: } else /* Most 1.2M drives */
1077: fl.fl_fd[fl.fl_unit].fd_trks = /* have 83 cyls! */
1078: (fl.fl_type[fl.fl_unit] == 2)
1079: ? FL_CYL_HDHI : FL_CYL_HDLO;
1080:
1081: /*
1082: * We next test for one or two sides:
1083: */
1084:
1085: if (fl.fl_rate[fl.fl_unit] == 0) { /* If diskette is */
1086: fl.fl_fd[fl.fl_unit].fd_nhds = 2; /* high-density it*/
1087: goto DiskEstablished; /* will have two */
1088: } /* sides. */
1089:
1090: /*
1091: * If the diskette is requested by caller as low density
1092: * we use the specified number of sides------
1093: */
1094:
1095: if (fdata[fkind(bp->b_dev)].fd_nspt < 12) {
1096: fl.fl_fd[fl.fl_unit].fd_nhds =
1097: fdata[fkind(bp->b_dev)].fd_nhds;
1098: goto DiskEstablished;
1099: }
1100:
1101: /*
1102: * --otherwise we check to see:
1103: */
1104:
1105: fdcPut(CMDRDID); /* Just try to read ANY sector*/
1106: fdcPut(fl.fl_unit | 0x04); /* ID from side two. */
1107: fl.fl_state = SSIDTST;
1108: break;
1109:
1110: case SSIDTST: /* If we succeeded, we have */
1111: T_HAL(0x40000, printf("SSIDTST "));
1112: /* 2 sides, else we have 1. */
1113: fl.fl_fd[fl.fl_unit].fd_nhds = ((fdc.fdc_ncmdstat < 7)
1114: || ((fdc.fdc_cmdstat[0] & ST0_IC) != ST0_NT) ) ? 1 : 2;
1115:
1116: /*
1117: * So now we now know all about the diskette!
1118: */
1119: DiskEstablished:
1120: fl.fl_fd[fl.fl_unit].fd_size = fl.fl_fd[fl.fl_unit].fd_nhds
1121: * fl.fl_fd[fl.fl_unit].fd_trks
1122: * fl.fl_fd[fl.fl_unit].fd_nspt;
1123:
1124: if (fl_disp) {
1125: printf("fl%d: rate=%d, sctrs/trk=%d, hds=%d, cyls=%d,"
1126: " size=%d, intlv=%d, stp=%d\n",
1127: fl.fl_unit,
1128: fl.fl_rate[fl.fl_unit],
1129: fl.fl_fd[fl.fl_unit].fd_nspt,
1130: fl.fl_fd[fl.fl_unit].fd_nhds,
1131: fl.fl_fd[fl.fl_unit].fd_trks,
1132: fl.fl_fd[fl.fl_unit].fd_size,
1133: fl_intlv_ct,
1134: fl.fl_2step[fl.fl_unit]+1);
1135: }
1136:
1137: RateKnown:
1138: /*
1139: * Set data rate if changed.
1140: */
1141: if (fl.fl_rate_set != (i = fl.fl_rate[fl.fl_unit])) {
1142: fl.fl_rate_set = i;
1143: fdcRate(fl.fl_rate_set);
1144: }
1145:
1146: /*
1147: * Next we must convert the ordinal block number to
1148: * cylinder/head/sector form.
1149: */
1150: fl.fl_fsec = (fl.fl_secn % fl.fl_fd[fl.fl_unit].fd_nspt) + 1;
1151:
1152: /*
1153: * Seek cylinder by cylinder (XENIX/DOS compatible).
1154: */
1155: if (fl.fl_hbyh) {
1156: fl.fl_head = fl.fl_secn / fl.fl_fd[fl.fl_unit].fd_nspt;
1157: fl.fl_fcyl = fl.fl_head / fl.fl_fd[fl.fl_unit].fd_nhds;
1158: fl.fl_head = fl.fl_head % fl.fl_fd[fl.fl_unit].fd_nhds;
1159: }
1160:
1161: /*
1162: * Seek surface by surface.
1163: */
1164: else {
1165: fl.fl_fcyl = fl.fl_secn / fl.fl_fd[fl.fl_unit].fd_nspt;
1166: fl.fl_head = fl.fl_fcyl / fl.fl_fd[fl.fl_unit].fd_trks;
1167: fl.fl_fcyl = fl.fl_fcyl % fl.fl_fd[fl.fl_unit].fd_trks;
1168: }
1169: /* Don't seek unless we have to. */
1170: if (fl.fl_fcyl == fl.fl_incal[fl.fl_unit])
1171: goto Sought; /* Past tense of seek. */
1172:
1173: fl.fl_incal[fl.fl_unit] = fl.fl_fcyl; /* Save new cylinder. */
1174:
1175: if ((fl.fl_fd[fl.fl_unit].fd_trks < 45)
1176: && (fl.fl_type[fl.fl_unit] != 1)) {
1177:
1178: /* If disk is around 40 tracks*/
1179: /* and drive is not 40 track- */
1180: /* -use double step. */
1181: fdcSeek(fl.fl_unit, fl.fl_head, (fl.fl_fcyl << 1));
1182:
1183: } else {
1184: /* Single step. */
1185: fdcSeek(fl.fl_unit, fl.fl_head, fl.fl_fcyl);
1186: }
1187:
1188: fl.fl_state = SHDLY;
1189: break;
1190:
1191: case SHDLY:
1192: T_HAL(0x40000, printf("SHDLY "));
1193: /*
1194: * Delay for minimum 15 milliseconds after seek before w/fmt.
1195: * 2 clock ticks would give 10-20 millisecond (100 Hz clock).
1196: * 3 clock ticks gives 20-30 millisecond (100 Hz clock).
1197: */
1198: if (bp->b_req != BREAD) {
1199: timeout(&fltim, 3, fldelay, SRDWR);
1200: fl.fl_state = SDELAY;
1201: break;
1202: }
1203: /* no break */
1204:
1205: case SRDWR:
1206: T_HAL(0x40000, printf("SRDWR "));
1207: Sought:
1208: /*
1209: * Disable watchdog timer while waiting to lock DMA controller.
1210: */
1211: fl.fl_time[fl.fl_unit] = -1;
1212:
1213: /*
1214: * Next state will be DMA locked state.
1215: */
1216: fl.fl_state = SLOCK;
1217:
1218: /*
1219: * If DMA controller locked by someone else, exit for now.
1220: */
1221: if (dmalock(&fldmalck, flfsm, 0) != 0)
1222: return;
1223:
1224: case SLOCK:
1225: T_HAL(0x40000, printf("SLOCK "));
1226: /*
1227: * Reset watchdog timer to restart timeout sequence.
1228: */
1229:
1230: fl.fl_time[fl.fl_unit] = 0;
1231:
1232: flcmd = CMDRDAT;
1233: fl.fl_wflag = 0;
1234:
1235: if (fl_clrng_cd == 0)
1236: if (bp->b_req == BWRITE) {
1237: fl.fl_wflag = 1;
1238: flcmd = CMDWDAT;
1239: }
1240:
1241: else if (bp->b_req == BFLFMT) {
1242: fl.fl_wflag = 1;
1243: flcmd = CMDFMT;
1244:
1245: if(!dmaon(DMA_CH2, P2P(fl.fl_addr),bp->b_count,
1246: fl.fl_wflag))
1247: goto straddle;
1248:
1249: else
1250: goto command;
1251: }
1252:
1253: if (dmaon(DMA_CH2, P2P(fl.fl_addr), 512, fl.fl_wflag) == 0) {
1254: straddle:
1255: devmsg(bp->b_dev, "fd: DMA page straddle at %x:%x",
1256: fl.fl_addr);
1257: dmaunlock(&fldmalck);
1258: bp->b_flag |= BFERR;
1259: fldone(bp);
1260: goto again;
1261: }
1262: command:
1263: dmago(DMA_CH2);
1264: fdcPut(flcmd);
1265: fdcPut((fl.fl_head<<2) | fl.fl_unit);
1266:
1267: if (bp->b_req == BFLFMT) {
1268: fdcPut(fl.fl_fd[fl.fl_unit].fd_N); /* N */
1269: fdcPut(fl.fl_fd[fl.fl_unit].fd_nspt); /* SC */
1270: fdcPut(fl.fl_fd[fl.fl_unit].fd_FGPL); /* GPL */
1271: fdcPut(0xF6); /* D */
1272: }
1273:
1274: else {
1275: fdcPut(fl.fl_fcyl);
1276: fdcPut(fl.fl_head);
1277: fdcPut(fl.fl_fsec);
1278: fdcPut(fl.fl_fd[fl.fl_unit].fd_N); /* N */
1279: fdcPut(fl.fl_fd[fl.fl_unit].fd_nspt); /* EOT */
1280: fdcPut(fl.fl_fd[fl.fl_unit].fd_GPL[fl.fl_rate_set]);
1281: /* GPL */
1282: fdcPut(0xFF); /* DTL */
1283: }
1284:
1285: fl.fl_state = SENDIO;
1286: break;
1287:
1288: case SENDIO:
1289: T_HAL(0x40000, printf("SENDIO "));
1290: fl.fl_time[fl.fl_unit] = 0;
1291: dmaoff(DMA_CH2);
1292: dmaunlock(&fldmalck);
1293:
1294: if (fl_clrng_cd) {
1295: fl.fl_state = SIDLE;
1296: wakeup(&fl.fl_state);
1297: goto again;
1298: }
1299:
1300: /*
1301: * We now check for errors. If the error is a data
1302: * CRC error, we KNOW we're on the correct track, and
1303: * we just retry the read once before recalibrating.
1304: * We recalibrate for all other errors.
1305: */
1306: if ((fdc.fdc_cmdstat[0] & ST0_IC) != ST0_NT) {
1307: if (++fl.fl_nerr < 5) {
1308: if (fdc.fdc_cmdstat[2] & ST2_DD) {
1309: if (fl.fl_nerr & 1)
1310: goto SetSEEKState;
1311: else
1312: goto Ask4Recal;
1313: } else {
1314: Ask4Recal:
1315: fl.fl_incal[fl.fl_unit] = -1;
1316: SetSEEKState:
1317: fl.fl_state = SSEEK;
1318: }
1319: } else {
1320: fdcStatus(); /* Total failure; */
1321: bp->b_flag |= BFERR; /* we give up. */
1322: fldone(bp);
1323: }
1324: }
1325:
1326: else if (--fl.fl_nsec == 0) {
1327: bp->b_resid = 0;
1328: fldone(bp);
1329: }
1330:
1331: else {
1332: ++fl.fl_secn;
1333: fl.fl_addr += 512; /* 512 == fl.fl_fd.fd_nbps */
1334: fl.fl_state = SSEEK;
1335: }
1336:
1337: /*
1338: * Delay for minimum 1.5 msecs after writing before seek.
1339: */
1340: if (fl.fl_wflag) {
1341: timeout(&fltim, 2, fldelay, fl.fl_state);
1342: fl.fl_state = SDELAY;
1343: break;
1344: }
1345:
1346: goto again;
1347:
1348: case SDELAY:
1349: T_HAL(0x40000, printf("SDELAY "));
1350: /*
1351: * Ignore interrupts until timeout occurs.
1352: */
1353: break;
1354:
1355: default:
1356: panic("fds");
1357: }
1358: }
1359:
1360: /*
1361: * Delay before initiating next operation.
1362: * This allows the floppy motor to turn on,
1363: * the head to settle before writing,
1364: * the erase head to turn off after writing, etc.
1365: */
1366: static void
1367: fldelay(state)
1368: int state;
1369: {
1370: int s;
1371:
1372: s = sphi();
1373: if (fl.fl_state == SDELAY) {
1374: fl.fl_state = state;
1375: flfsm();
1376: }
1377: spl(s);
1378: }
1379:
1380: /*
1381: * The flrate function returns the data rate for the flopen and flfsm routines.
1382: */
1383: static int
1384: flrate(dev)
1385: register dev_t dev;
1386: {
1387: register int unit = funit(dev);
1388: register int rate = frates[fl.fl_type[unit]].fl_hi_rate;
1389:
1390: if ((rate == -1) || (fdata[fkind(dev)].fd_nspt < 15))
1391: rate = frates[fl.fl_type[unit]].fl_lo_rate;
1392:
1393: return(rate);
1394: }
1395:
1396: /*
1397: * fldone() returns current request to operating system.
1398: */
1399: static void
1400: fldone(bp)
1401: register BUF * bp;
1402: {
1403: fl.fl_actf = bp->b_actf;
1404: fl.fl_state = SIDLE;
1405: bdone(bp);
1406: wakeup(&fl.fl_state);
1407: }
1408:
1409: /*
1410: * The recovery routine resets and reprograms the floppy controller,
1411: * and discards any queued requests on the current drive.
1412: * This is required if the floppy door is open, or diskette is missing.
1413: */
1414: static void
1415: flrecov()
1416: {
1417: register int x;
1418:
1419: if (FL_DSK_CH_PROB)
1420: jopen = 1;
1421:
1422: /*
1423: * Disable DMA transfer.
1424: * Reset floppy controller.
1425: */
1426: dmaoff(DMA_CH2);
1427:
1428: /*
1429: * Unlock the controller if locked by us.
1430: */
1431:
1432: outb(FDCDOR, 0);
1433: fl.fl_state = SIDLE;
1434: wakeup(&fl.fl_state);
1435: dmaunlock(&fldmalck); /* Ensures 14 clock cycles */
1436: outb(FDCDOR, DORNMR | DORIEN);
1437:
1438: fl.fl_mstatus = 0; /* No motors on */
1439: fl.fl_selected_unit = -1; /* No unit selected */
1440:
1441: /*
1442: * Program floppy controller.
1443: */
1444: fdcSpecify(fl_srt, fl_hut, fl_hlt); /* Forces wait */
1445:
1446: /*
1447: * Program transfer bps.
1448: */
1449: fdcRate(fl.fl_rate_set);
1450:
1451: /*
1452: * Drives are no longer in calibration.
1453: */
1454: for (x = 0; x < MAXDRVS; x++)
1455: fl.fl_incal[1] = -1;
1456:
1457: /*
1458: * Abort all block requests on current drive after 1st recov attempt.
1459: */
1460: if (fl.fl_actf) {
1461: printf("fd%d: <Door Open>\n", fl.fl_unit); /* Message */
1462: clrQ(fl.fl_actf->b_dev); /* Dump pending reqs. */
1463: fl.fl_dsk_chngd[fl.fl_unit] = 1; /* Make disk changed. */
1464: }
1465:
1466: /*
1467: * Delay before setting controller state to idle.
1468: * This gives time for spurious floppy interrupts to occur.
1469: * NOTE: Can't call flfsm(), since it may call us (future revision).
1470: */
1471: timeout(&fltim, HZ/4, fldelay, SIDLE);
1472: fl.fl_state = SDELAY;
1473: }
1474:
1475: /*
1476: * This routine is called by the
1477: * clock handler every second. If the drive
1478: * has been idle for a long time it turns off
1479: * the motor and shuts off the timeouts.
1480: */
1481: static int
1482: fltimeout()
1483: {
1484: register int unit;
1485: register int mask;
1486: register int s;
1487:
1488: s = sphi();
1489:
1490: /*
1491: * Scan all drives, looking for motor timeouts.
1492: */
1493: for (unit=0, mask=0x10; unit < MAXDRVS; unit++, mask <<= 1) {
1494:
1495: /*
1496: * Ignore drives which aren't spinning.
1497: */
1498: if ((fl.fl_mstatus & mask) == 0)
1499: continue;
1500:
1501: /*
1502: * If timer is disabled (i.e. we are waiting for the DMA
1503: * controller), go on to the next drive.
1504: */
1505: if (fl.fl_time[unit] < 0)
1506: continue;
1507:
1508: /*
1509: * Leave recently accessed (in last 4 seconds) drives spinning.
1510: */
1511: if (++fl.fl_time[unit] < MTIMER)
1512: continue;
1513:
1514: /*
1515: * Timeout drives which have been inactive for 5 seconds.
1516: */
1517: fl.fl_mstatus &= ~mask;
1518: if (unit == fl.fl_selected_unit)
1519: fl.fl_selected_unit = -1;
1520:
1521: /*
1522: * Not selected drive, or selected drive is idle.
1523: */
1524: if ((unit != fl.fl_unit) || (fl.fl_state == SIDLE))
1525: continue;
1526:
1527: /*
1528: * Active drive did not complete operation within 5 seconds.
1529: * Attempt recovery.
1530: */
1531: flrecov();
1532:
1533: /*
1534: * Initiate next block request.
1535: */
1536: if (fl.fl_state == SIDLE)
1537: flfsm();
1538: }
1539:
1540: /*
1541: * Physically turn off drives which timed out.
1542: */
1543: outb(FDCDOR, DORNMR | DORIEN | fl.fl_mstatus | fl.fl_unit);
1544:
1545: /*
1546: * Stop checking once all drives have been stopped.
1547: */
1548: if (fl.fl_mstatus == 0)
1549: setFlTimer(0);
1550:
1551: spl(s);
1552: }
1553:
1554: static void
1555: flDrvSelect()
1556: {
1557: fl.fl_time[fl.fl_unit] = 0; /* Start motor-on timeout. */
1558: fl.fl_mstatus |= fl.fl_mask;
1559: fdcDrvSelect(fl.fl_unit, 1); /* "1" for motor on */
1560: fl.fl_selected_unit = fl.fl_unit; /* This unit is running. */
1561: }
1562:
1563: /*
1564: * Get the drive status
1565: */
1566: static void
1567: flDrvStatus()
1568: {
1569: register int b;
1570: register int n = 0; /* # of status bytes read */
1571: register int i = 0; /* Timeout count */
1572: register int s;
1573:
1574: s = sphi();
1575:
1576: flDrvSelect(); /* Be sure drive is selected */
1577:
1578: /* Issue a sense drive status command. */
1579: fdcDrvStatus(fl.fl_unit, 0);
1580:
1581: /* Stash Drive Status results. */
1582: for (;;) {
1583: /* Check for incoming signal. */
1584: spl(s);
1585: if (nondsig()) { /* signal? */
1586: u.u_error = EINTR;
1587: break;
1588: }
1589: s = sphi();
1590:
1591: /* Copy data byte from FDC into fl_drvstat array. */
1592: b = fdcGet();
1593: if (b == -1)
1594: break;
1595: if (n < FL_NUM_DRV_STAT)
1596: fl.fl_drvstat[n++] = b;
1597: }
1598: fl.fl_ndrvstat = n;
1599: spl(s);
1600: }
1601:
1602: static void
1603: flIntHandler()
1604: {
1605: /*
1606: * Need to get FDC status from result phase, and clear interrupt
1607: * that may have been generated by diskette change or seek/recal
1608: * complete.
1609: */
1610: fdcSense();
1611:
1612: if (fl.fl_state != SIDLE)
1613: flfsm();
1614: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.