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