]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/fdc/fdc.c
This commit was generated by cvs2svn to compensate for changes in r41980,
[FreeBSD/FreeBSD.git] / sys / dev / fdc / fdc.c
1 /*
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Don Ahn.
7  *
8  * Libretto PCMCIA floppy support by David Horwitt (dhorwitt@ucsd.edu)
9  * aided by the Linux floppy driver modifications from David Bateman
10  * (dbateman@eng.uts.edu.au).
11  *
12  * Copyright (c) 1993, 1994 by
13  *  jc@irbs.UUCP (John Capo)
14  *  vak@zebub.msk.su (Serge Vakulenko)
15  *  ache@astral.msk.su (Andrew A. Chernov)
16  *
17  * Copyright (c) 1993, 1994, 1995 by
18  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
19  *  dufault@hda.com (Peter Dufault)
20  *
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions
23  * are met:
24  * 1. Redistributions of source code must retain the above copyright
25  *    notice, this list of conditions and the following disclaimer.
26  * 2. Redistributions in binary form must reproduce the above copyright
27  *    notice, this list of conditions and the following disclaimer in the
28  *    documentation and/or other materials provided with the distribution.
29  * 3. All advertising materials mentioning features or use of this software
30  *    must display the following acknowledgement:
31  *      This product includes software developed by the University of
32  *      California, Berkeley and its contributors.
33  * 4. Neither the name of the University nor the names of its contributors
34  *    may be used to endorse or promote products derived from this software
35  *    without specific prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  *      from:   @(#)fd.c        7.4 (Berkeley) 5/25/91
50  *      $Id: fd.c,v 1.128 1998/12/12 08:16:01 imp Exp $
51  *
52  */
53
54 #include "ft.h"
55 #if NFT < 1
56 #undef NFDC
57 #endif
58 #include "fd.h"
59 #include "opt_devfs.h"
60 #include "opt_fdc.h"
61
62 #if NFDC > 0
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/kernel.h>
67 #include <sys/conf.h>
68 #include <sys/fcntl.h>
69 #include <machine/clock.h>
70 #include <machine/ioctl_fd.h>
71 #include <sys/disklabel.h>
72 #include <sys/buf.h>
73 #include <sys/devicestat.h>
74 #include <sys/malloc.h>
75 #include <sys/proc.h>
76 #include <sys/syslog.h>
77 #include <i386/isa/isa.h>
78 #include <i386/isa/isa_device.h>
79 #include <i386/isa/fdreg.h>
80 #include <i386/isa/fdc.h>
81 #include <i386/isa/rtc.h>
82 #include <machine/stdarg.h>
83 #if NFT > 0
84 #include <sys/ftape.h>
85 #include <i386/isa/ftreg.h>
86 #endif
87 #ifdef  DEVFS
88 #include <sys/devfsext.h>
89 #endif  /* DEVFS */
90
91 /* misuse a flag to identify format operation */
92 #define B_FORMAT B_XXX
93
94 /* configuration flags */
95 #define FDC_PRETEND_D0  (1 << 0)        /* pretend drive 0 to be there */
96 #ifdef FDC_YE
97 #define FDC_IS_PCMCIA  (1 << 1)         /* if successful probe, then it's
98                                            a PCMCIA device */
99 #endif
100
101 /* internally used only, not really from CMOS: */
102 #define RTCFDT_144M_PRETENDED   0x1000
103
104 /*
105  * this biotab field doubles as a field for the physical unit number
106  * on the controller
107  */
108 #define id_physid id_scsiid
109
110 /* error returns for fd_cmd() */
111 #define FD_FAILED -1
112 #define FD_NOT_VALID -2
113 #define FDC_ERRMAX      100     /* do not log more */
114
115 #define NUMTYPES 14
116 #define NUMDENS  (NUMTYPES - 6)
117
118 /* These defines (-1) must match index for fd_types */
119 #define F_TAPE_TYPE     0x020   /* bit for fd_types to indicate tape */
120 #define NO_TYPE         0       /* must match NO_TYPE in ft.c */
121 #define FD_1720         1
122 #define FD_1480         2
123 #define FD_1440         3
124 #define FD_1200         4
125 #define FD_820          5
126 #define FD_800          6
127 #define FD_720          7
128 #define FD_360          8
129
130 #define FD_1480in5_25   9
131 #define FD_1440in5_25   10
132 #define FD_820in5_25    11
133 #define FD_800in5_25    12
134 #define FD_720in5_25    13
135 #define FD_360in5_25    14
136
137
138 static struct fd_type fd_types[NUMTYPES] =
139 {
140 { 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
141 { 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
142 { 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
143 { 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /*  1.2M in HD 5.25/3.5 */
144 { 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /*  820K in HD 3.5in */
145 { 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /*  800K in HD 3.5in */
146 {  9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /*  720K in HD 3.5in */
147 {  9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /*  360K in DD 5.25in */
148
149 { 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
150 { 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
151 { 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /*  820K in HD 5.25in */
152 { 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /*  800K in HD 5.25in */
153 {  9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /*  720K in HD 5.25in */
154 {  9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /*  360K in HD 5.25in */
155 };
156
157 #define DRVS_PER_CTLR 2         /* 2 floppies */
158
159 /***********************************************************************\
160 * Per controller structure.                                             *
161 \***********************************************************************/
162 struct fdc_data fdc_data[NFDC];
163
164 /***********************************************************************\
165 * Per drive structure.                                                  *
166 * N per controller  (DRVS_PER_CTLR)                                     *
167 \***********************************************************************/
168 static struct fd_data {
169         struct  fdc_data *fdc;  /* pointer to controller structure */
170         int     fdsu;           /* this units number on this controller */
171         int     type;           /* Drive type (FD_1440...) */
172         struct  fd_type *ft;    /* pointer to the type descriptor */
173         int     flags;
174 #define FD_OPEN         0x01    /* it's open            */
175 #define FD_ACTIVE       0x02    /* it's active          */
176 #define FD_MOTOR        0x04    /* motor should be on   */
177 #define FD_MOTOR_WAIT   0x08    /* motor coming up      */
178         int     skip;
179         int     hddrv;
180 #define FD_NO_TRACK -2
181         int     track;          /* where we think the head is */
182         int     options;        /* user configurable options, see ioctl_fd.h */
183         struct  callout_handle toffhandle;
184         struct  callout_handle tohandle;
185         struct  devstat device_stats;
186 #ifdef DEVFS
187         void    *bdevs[1 + NUMDENS + MAXPARTITIONS];
188         void    *cdevs[1 + NUMDENS + MAXPARTITIONS];
189 #endif
190 } fd_data[NFD];
191
192 /***********************************************************************\
193 * Throughout this file the following conventions will be used:          *
194 * fd is a pointer to the fd_data struct for the drive in question       *
195 * fdc is a pointer to the fdc_data struct for the controller            *
196 * fdu is the floppy drive unit number                                   *
197 * fdcu is the floppy controller unit number                             *
198 * fdsu is the floppy drive unit number on that controller. (sub-unit)   *
199 \***********************************************************************/
200
201 #if NFT > 0
202 int ftopen(dev_t, int);
203 int ftintr(ftu_t ftu);
204 int ftclose(dev_t, int);
205 void ftstrategy(struct buf *);
206 int ftioctl(dev_t, unsigned long, caddr_t, int, struct proc *);
207 int ftdump(dev_t);
208 int ftsize(dev_t);
209 int ftattach(struct isa_device *, struct isa_device *, int);
210 #endif
211
212 #ifdef FDC_YE
213 #include "card.h"
214 static int yeattach(struct isa_device *);
215 #endif
216
217 /* autoconfig functions */
218 static int fdprobe(struct isa_device *);
219 static int fdattach(struct isa_device *);
220
221 /* needed for ft driver, thus exported */
222 int in_fdc(fdcu_t);
223 int out_fdc(fdcu_t, int);
224
225 /* internal functions */
226 static void set_motor(fdcu_t, int, int);
227 #  define TURNON 1
228 #  define TURNOFF 0
229 static timeout_t fd_turnoff;
230 static timeout_t fd_motor_on;
231 static void fd_turnon(fdu_t);
232 static void fdc_reset(fdc_p);
233 static int fd_in(fdcu_t, int *);
234 static void fdstart(fdcu_t);
235 static timeout_t fd_iotimeout;
236 static timeout_t fd_pseudointr;
237 static ointhand2_t fdintr;
238 static int fdstate(fdcu_t, fdc_p);
239 static int retrier(fdcu_t);
240 static int fdformat(dev_t, struct fd_formb *, struct proc *);
241
242 static int enable_fifo(fdc_p fdc);
243
244 static int fifo_threshold = 8;  /* XXX: should be accessible via sysctl */
245
246
247 #define DEVIDLE         0
248 #define FINDWORK        1
249 #define DOSEEK          2
250 #define SEEKCOMPLETE    3
251 #define IOCOMPLETE      4
252 #define RECALCOMPLETE   5
253 #define STARTRECAL      6
254 #define RESETCTLR       7
255 #define SEEKWAIT        8
256 #define RECALWAIT       9
257 #define MOTORWAIT       10
258 #define IOTIMEDOUT      11
259 #define RESETCOMPLETE   12
260 #ifdef FDC_YE
261 #define PIOREAD         13
262 #endif
263
264 #ifdef  FDC_DEBUG
265 static char const * const fdstates[] =
266 {
267 "DEVIDLE",
268 "FINDWORK",
269 "DOSEEK",
270 "SEEKCOMPLETE",
271 "IOCOMPLETE",
272 "RECALCOMPLETE",
273 "STARTRECAL",
274 "RESETCTLR",
275 "SEEKWAIT",
276 "RECALWAIT",
277 "MOTORWAIT",
278 "IOTIMEDOUT",
279 "RESETCOMPLETE",
280 #ifdef FDC_YE
281 "PIOREAD",
282 #endif
283 };
284
285 /* CAUTION: fd_debug causes huge amounts of logging output */
286 static int volatile fd_debug = 0;
287 #define TRACE0(arg) if(fd_debug) printf(arg)
288 #define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
289 #else /* FDC_DEBUG */
290 #define TRACE0(arg)
291 #define TRACE1(arg1, arg2)
292 #endif /* FDC_DEBUG */
293
294 #ifdef FDC_YE
295 #if NCARD > 0
296 #include <sys/select.h>
297 #include <pccard/cardinfo.h>
298 #include <pccard/driver.h>
299 #include <pccard/slot.h>
300
301 /*
302  *      PC-Card (PCMCIA) specific code.
303  */
304 static int yeinit(struct pccard_devinfo *);             /* init device */
305 static void yeunload(struct pccard_devinfo *);          /* Disable driver */
306 static int yeintr(struct pccard_devinfo *);             /* Interrupt handler */
307
308 static struct pccard_device ye_info = {
309         "fdc",
310         yeinit,
311         yeunload,
312         yeintr,
313         0,                      /* Attributes - presently unused */
314         &bio_imask              /* Interrupt mask for device */
315 };
316
317 DATA_SET(pccarddrv_set, ye_info);
318
319 /*
320  * this is the secret PIO data port (offset from base)
321  */
322 #define FDC_YE_DATAPORT 6
323
324 /*
325  *      Initialize the device - called from Slot manager.
326  */
327 static int yeinit(struct pccard_devinfo *devi)
328 {
329         fdc_p fdc = &fdc_data[devi->isahd.id_unit];
330
331         /* validate unit number. */
332         if (devi->isahd.id_unit >= NFDC)
333                 return(ENODEV);
334         fdc->baseport = devi->isahd.id_iobase;
335         /*
336          * reset controller
337          */
338         outb(fdc->baseport+FDOUT, 0);
339         DELAY(100);
340         outb(fdc->baseport+FDOUT, FDO_FRST);
341
342         /*
343          * wire into system
344          */
345         if (yeattach(&devi->isahd) == 0)
346                 return(ENXIO);
347
348         return(0);
349 }
350
351 /*
352  *      yeunload - unload the driver and clear the table.
353  *      XXX TODO:
354  *      This is usually called when the card is ejected, but
355  *      can be caused by a modunload of a controller driver.
356  *      The idea is to reset the driver's view of the device
357  *      and ensure that any driver entry points such as
358  *      read and write do not hang.
359  */
360 static void yeunload(struct pccard_devinfo *devi)
361 {
362         if (fd_data[devi->isahd.id_unit].type == NO_TYPE)
363                 return;
364
365         /*
366          * this prevents Fdopen() and fdstrategy() from attempting
367          * to access unloaded controller
368          */
369         fd_data[devi->isahd.id_unit].type = NO_TYPE;
370
371         printf("fdc%d: unload\n", devi->isahd.id_unit);
372 }
373
374 /*
375  *      yeintr - Shared interrupt called from
376  *      front end of PC-Card handler.
377  */
378 static int yeintr(struct pccard_devinfo *devi)
379 {
380         fdintr((fdcu_t)devi->isahd.id_unit);
381         return(1);
382 }
383 #endif /* NCARD > 0 */
384 #endif /* FDC_YE */
385
386
387 /* autoconfig structure */
388
389 struct  isa_driver fdcdriver = {
390         fdprobe, fdattach, "fdc",
391 };
392
393 static  d_open_t        Fdopen; /* NOTE, not fdopen */
394 static  d_read_t        fdread;
395 static  d_write_t       fdwrite;
396 static  d_close_t       fdclose;
397 static  d_ioctl_t       fdioctl;
398 static  d_strategy_t    fdstrategy;
399
400 /* even if SLICE defined, these are needed for the ft support. */
401 #define CDEV_MAJOR 9
402 #define BDEV_MAJOR 2
403
404
405 static struct cdevsw fd_cdevsw = {
406           Fdopen,       fdclose,        fdread, fdwrite,
407           fdioctl,      nostop,         nullreset,      nodevtotty,
408           seltrue,      nommap,         fdstrategy,     "fd",
409           NULL,         -1,             nodump,         nopsize,
410           D_DISK,       0,              -1 };
411
412
413 static struct isa_device *fdcdevs[NFDC];
414
415
416 static int
417 fdc_err(fdcu_t fdcu, const char *s)
418 {
419         fdc_data[fdcu].fdc_errs++;
420         if(s) {
421                 if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX)
422                         printf("fdc%d: %s", fdcu, s);
423                 else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
424                         printf("fdc%d: too many errors, not logging any more\n",
425                             fdcu);
426         }
427
428         return FD_FAILED;
429 }
430
431 /*
432  * fd_cmd: Send a command to the chip.  Takes a varargs with this structure:
433  * Unit number,
434  * # of output bytes, output bytes as ints ...,
435  * # of input bytes, input bytes as ints ...
436  */
437
438 static int
439 fd_cmd(fdcu_t fdcu, int n_out, ...)
440 {
441         u_char cmd;
442         int n_in;
443         int n;
444         va_list ap;
445
446         va_start(ap, n_out);
447         cmd = (u_char)(va_arg(ap, int));
448         va_end(ap);
449         va_start(ap, n_out);
450         for (n = 0; n < n_out; n++)
451         {
452                 if (out_fdc(fdcu, va_arg(ap, int)) < 0)
453                 {
454                         char msg[50];
455                         snprintf(msg, sizeof(msg),
456                                 "cmd %x failed at out byte %d of %d\n",
457                                 cmd, n + 1, n_out);
458                         return fdc_err(fdcu, msg);
459                 }
460         }
461         n_in = va_arg(ap, int);
462         for (n = 0; n < n_in; n++)
463         {
464                 int *ptr = va_arg(ap, int *);
465                 if (fd_in(fdcu, ptr) < 0)
466                 {
467                         char msg[50];
468                         snprintf(msg, sizeof(msg),
469                                 "cmd %02x failed at in byte %d of %d\n",
470                                 cmd, n + 1, n_in);
471                         return fdc_err(fdcu, msg);
472                 }
473         }
474
475         return 0;
476 }
477
478 static int 
479 enable_fifo(fdc_p fdc)
480 {
481         int i, j;
482
483         if ((fdc->flags & FDC_HAS_FIFO) == 0) {
484                 
485                 /*
486                  * XXX: 
487                  * Cannot use fd_cmd the normal way here, since
488                  * this might be an invalid command. Thus we send the
489                  * first byte, and check for an early turn of data directon.
490                  */
491                 
492                 if (out_fdc(fdc->fdcu, I8207X_CONFIGURE) < 0)
493                         return fdc_err(fdc->fdcu, "Enable FIFO failed\n");
494                 
495                 /* If command is invalid, return */
496                 j = 100000;
497                 while ((i = inb(fdc->baseport + FDSTS) & (NE7_DIO | NE7_RQM))
498                        != NE7_RQM && j-- > 0)
499                         if (i == (NE7_DIO | NE7_RQM)) {
500                                 fdc_reset(fdc);
501                                 return FD_FAILED;
502                         }
503                 if (j<0 || 
504                     fd_cmd(fdc->fdcu, 3,
505                            0, (fifo_threshold - 1) & 0xf, 0, 0) < 0) {
506                         fdc_reset(fdc);
507                         return fdc_err(fdc->fdcu, "Enable FIFO failed\n");
508                 }
509                 fdc->flags |= FDC_HAS_FIFO;
510                 return 0;
511         }
512         if (fd_cmd(fdc->fdcu, 4,
513                    I8207X_CONFIGURE, 0, (fifo_threshold - 1) & 0xf, 0, 0) < 0)
514                 return fdc_err(fdc->fdcu, "Re-enable FIFO failed\n");
515         return 0;
516 }
517
518 static int
519 fd_sense_drive_status(fdc_p fdc, int *st3p)
520 {
521         int st3;
522
523         if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
524         {
525                 return fdc_err(fdc->fdcu, "Sense Drive Status failed\n");
526         }
527         if (st3p)
528                 *st3p = st3;
529
530         return 0;
531 }
532
533 static int
534 fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
535 {
536         int st0, cyl;
537
538         int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0);
539
540         if (ret)
541         {
542                 (void)fdc_err(fdc->fdcu,
543                               "sense intr err reading stat reg 0\n");
544                 return ret;
545         }
546
547         if (st0p)
548                 *st0p = st0;
549
550         if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV)
551         {
552                 /*
553                  * There doesn't seem to have been an interrupt.
554                  */
555                 return FD_NOT_VALID;
556         }
557
558         if (fd_in(fdc->fdcu, &cyl) < 0)
559         {
560                 return fdc_err(fdc->fdcu, "can't get cyl num\n");
561         }
562
563         if (cylp)
564                 *cylp = cyl;
565
566         return 0;
567 }
568
569
570 static int
571 fd_read_status(fdc_p fdc, int fdsu)
572 {
573         int i, ret;
574
575         for (i = 0; i < 7; i++)
576         {
577                 /*
578                  * XXX types are poorly chosen.  Only bytes can by read
579                  * from the hardware, but fdc->status[] wants u_ints and
580                  * fd_in() gives ints.
581                  */
582                 int status;
583
584                 ret = fd_in(fdc->fdcu, &status);
585                 fdc->status[i] = status;
586                 if (ret != 0)
587                         break;
588         }
589
590         if (ret == 0)
591                 fdc->flags |= FDC_STAT_VALID;
592         else
593                 fdc->flags &= ~FDC_STAT_VALID;
594
595         return ret;
596 }
597
598 /****************************************************************************/
599 /*                      autoconfiguration stuff                             */
600 /****************************************************************************/
601
602 /*
603  * probe for existance of controller
604  */
605 static int
606 fdprobe(struct isa_device *dev)
607 {
608         fdcu_t  fdcu = dev->id_unit;
609         if(fdc_data[fdcu].flags & FDC_ATTACHED)
610         {
611                 printf("fdc%d: unit used multiple times\n", fdcu);
612                 return 0;
613         }
614
615         fdcdevs[fdcu] = dev;
616         fdc_data[fdcu].baseport = dev->id_iobase;
617
618         /* First - lets reset the floppy controller */
619         outb(dev->id_iobase+FDOUT, 0);
620         DELAY(100);
621         outb(dev->id_iobase+FDOUT, FDO_FRST);
622
623         /* see if it can handle a command */
624         if (fd_cmd(fdcu,
625                    3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
626                    0))
627         {
628                 return(0);
629         }
630 #ifdef FDC_YE
631         /*
632          * don't succeed on probe; wait
633          * for PCCARD subsystem to do it
634          */
635         if (dev->id_flags & FDC_IS_PCMCIA)
636                 return(0);
637 #endif
638         return (IO_FDCSIZE);
639 }
640
641 /*
642  * wire controller into system, look for floppy units
643  */
644 static int
645 fdattach(struct isa_device *dev)
646 {
647         unsigned fdt;
648         fdu_t   fdu;
649         fdcu_t  fdcu = dev->id_unit;
650         fdc_p   fdc = fdc_data + fdcu;
651         fd_p    fd;
652         int     fdsu, st0, st3, i;
653 #if NFT > 0
654         int     unithasfd;
655 #endif
656         struct isa_device *fdup;
657         int ic_type = 0;
658 #ifdef DEVFS
659         int     mynor;
660         int     typemynor;
661         int     typesize;
662 #endif
663
664         dev->id_ointr = fdintr;
665         fdc->fdcu = fdcu;
666         fdc->flags |= FDC_ATTACHED;
667         fdc->dmachan = dev->id_drq;
668         /* Acquire the DMA channel forever, The driver will do the rest */
669         isa_dma_acquire(fdc->dmachan);
670         isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
671         fdc->state = DEVIDLE;
672         /* reset controller, turn motor off, clear fdout mirror reg */
673         outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
674         bufq_init(&fdc->head);
675
676         /* check for each floppy drive */
677         for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
678                 if (fdup->id_iobase != dev->id_iobase)
679                         continue;
680                 fdu = fdup->id_unit;
681                 fd = &fd_data[fdu];
682                 if (fdu >= (NFD+NFT))
683                         continue;
684                 fdsu = fdup->id_physid;
685                 /* look up what bios thinks we have */
686                 switch (fdu) {
687                         case 0: if (dev->id_flags & FDC_PRETEND_D0)
688                                         fdt = RTCFDT_144M | RTCFDT_144M_PRETENDED;
689                                 else
690                                         fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
691                                 break;
692                         case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
693                                 break;
694                         default: fdt = RTCFDT_NONE;
695                                 break;
696                 }
697                 /* is there a unit? */
698                 if ((fdt == RTCFDT_NONE)
699 #if NFT > 0
700                     || (fdsu >= DRVS_PER_CTLR)) {
701 #else
702                 ) {
703                         fd->type = NO_TYPE;
704 #endif
705 #if NFT > 0
706                         /* If BIOS says no floppy, or > 2nd device */
707                         /* Probe for and attach a floppy tape.     */
708                         /* Tell FT if there was already a disk     */
709                         /* with this unit number found.            */
710
711                         unithasfd = 0;
712                         if (fdu < NFD && fd->type != NO_TYPE)
713                                 unithasfd = 1;
714                         if (ftattach(dev, fdup, unithasfd))
715                                 continue;
716                         if (fdsu < DRVS_PER_CTLR)
717                                 fd->type = NO_TYPE;
718 #endif
719                         continue;
720                 }
721
722                 /* select it */
723                 set_motor(fdcu, fdsu, TURNON);
724                 DELAY(1000000); /* 1 sec */
725
726                 if (ic_type == 0 &&
727                     fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0)
728                 {
729 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
730                         printf("fdc%d: ", fdcu);
731 #endif
732                         ic_type = (u_char)ic_type;
733                         switch( ic_type ) {
734                         case 0x80:
735 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
736                                 printf("NEC 765\n");
737 #endif
738                                 fdc->fdct = FDC_NE765;
739                                 break;
740                         case 0x81:
741 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
742                                 printf("Intel 82077\n");
743 #endif
744                                 fdc->fdct = FDC_I82077;
745                                 break;
746                         case 0x90:
747 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
748                                 printf("NEC 72065B\n");
749 #endif
750                                 fdc->fdct = FDC_NE72065;
751                                 break;
752                         default:
753 #ifdef FDC_PRINT_BOGUS_CHIPTYPE
754                                 printf("unknown IC type %02x\n", ic_type);
755 #endif
756                                 fdc->fdct = FDC_UNKNOWN;
757                                 break;
758                         }
759                         if (fdc->fdct != FDC_NE765 &&
760                             fdc->fdct != FDC_UNKNOWN && 
761                             enable_fifo(fdc) == 0) {
762                                 printf("fdc%d: FIFO enabled", fdcu);
763                                 printf(", %d bytes threshold\n", 
764                                     fifo_threshold);
765                         }
766                 }
767                 if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
768                     (st3 & NE7_ST3_T0)) {
769                         /* if at track 0, first seek inwards */
770                         /* seek some steps: */
771                         (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
772                         DELAY(300000); /* ...wait a moment... */
773                         (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
774                 }
775
776                 /* If we're at track 0 first seek inwards. */
777                 if ((fd_sense_drive_status(fdc, &st3) == 0) &&
778                     (st3 & NE7_ST3_T0)) {
779                         /* Seek some steps... */
780                         if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
781                                 /* ...wait a moment... */
782                                 DELAY(300000);
783                                 /* make ctrlr happy: */
784                                 (void)fd_sense_int(fdc, 0, 0);
785                         }
786                 }
787
788                 for(i = 0; i < 2; i++) {
789                         /*
790                          * we must recalibrate twice, just in case the
791                          * heads have been beyond cylinder 76, since most
792                          * FDCs still barf when attempting to recalibrate
793                          * more than 77 steps
794                          */
795                         /* go back to 0: */
796                         if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
797                                 /* a second being enough for full stroke seek*/
798                                 DELAY(i == 0? 1000000: 300000);
799
800                                 /* anything responding? */
801                                 if (fd_sense_int(fdc, &st0, 0) == 0 &&
802                                 (st0 & NE7_ST0_EC) == 0)
803                                         break; /* already probed succesfully */
804                         }
805                 }
806
807                 set_motor(fdcu, fdsu, TURNOFF);
808
809                 if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
810                         continue;
811
812                 fd->track = FD_NO_TRACK;
813                 fd->fdc = fdc;
814                 fd->fdsu = fdsu;
815                 fd->options = 0;
816                 callout_handle_init(&fd->toffhandle);
817                 callout_handle_init(&fd->tohandle);
818                 printf("fd%d: ", fdu);
819
820                 switch (fdt) {
821                 case RTCFDT_12M:
822                         printf("1.2MB 5.25in\n");
823                         fd->type = FD_1200;
824                         break;
825                 case RTCFDT_144M | RTCFDT_144M_PRETENDED:
826                         printf("config-pretended ");
827                         fdt = RTCFDT_144M;
828                         /* fallthrough */
829                 case RTCFDT_144M:
830                         printf("1.44MB 3.5in\n");
831                         fd->type = FD_1440;
832                         break;
833                 case RTCFDT_288M:
834                 case RTCFDT_288M_1:
835                         printf("2.88MB 3.5in - 1.44MB mode\n");
836                         fd->type = FD_1440;
837                         break;
838                 case RTCFDT_360K:
839                         printf("360KB 5.25in\n");
840                         fd->type = FD_360;
841                         break;
842                 case RTCFDT_720K:
843                         printf("720KB 3.5in\n");
844                         fd->type = FD_720;
845                         break;
846                 default:
847                         printf("unknown\n");
848                         fd->type = NO_TYPE;
849                         continue;
850                 }
851 #ifdef DEVFS
852                 mynor = fdu << 6;
853                 fd->bdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_BLK,
854                                                 UID_ROOT, GID_OPERATOR, 0640,
855                                                 "fd%d", fdu);
856                 fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR,
857                                                 UID_ROOT, GID_OPERATOR, 0640,
858                                                 "rfd%d", fdu);
859                 for (i = 1; i < 1 + NUMDENS; i++) {
860                         /*
861                          * XXX this and the lookup in Fdopen() should be
862                          * data driven.
863                          */
864                         switch (fd->type) {
865                         case FD_360:
866                                 if (i != FD_360)
867                                         continue;
868                                 break;
869                         case FD_720:
870                                 if (i != FD_720 && i != FD_800 && i != FD_820)
871                                         continue;
872                                 break;
873                         case FD_1200:
874                                 if (i != FD_360 && i != FD_720 && i != FD_800
875                                     && i != FD_820 && i != FD_1200
876                                     && i != FD_1440 && i != FD_1480)
877                                         continue;
878                                 break;
879                         case FD_1440:
880                                 if (i != FD_720 && i != FD_800 && i != FD_820
881                                     && i != FD_1200 && i != FD_1440
882                                     && i != FD_1480 && i != FD_1720)
883                                         continue;
884                                 break;
885                         }
886                         typesize = fd_types[i - 1].size / 2;
887                         /*
888                          * XXX all these conversions give bloated code and
889                          * confusing names.
890                          */
891                         if (typesize == 1476)
892                                 typesize = 1480;
893                         if (typesize == 1722)
894                                 typesize = 1720;
895                         typemynor = mynor | i;
896                         fd->bdevs[i] =
897                                 devfs_add_devswf(&fd_cdevsw, typemynor, DV_BLK,
898                                                  UID_ROOT, GID_OPERATOR, 0640,
899                                                  "fd%d.%d", fdu, typesize);
900                         fd->cdevs[i] =
901                                 devfs_add_devswf(&fd_cdevsw, typemynor, DV_CHR,
902                                                  UID_ROOT, GID_OPERATOR, 0640,
903                                                  "rfd%d.%d", fdu, typesize);
904                 }
905
906                 for (i = 0; i < MAXPARTITIONS; i++) {
907                         fd->bdevs[1 + NUMDENS + i] = devfs_makelink(fd->bdevs[0],
908                                            "fd%d%c", fdu, 'a' + i);
909                         fd->cdevs[1 + NUMDENS + i] =
910                                 devfs_makelink(fd->cdevs[0],
911                                            "rfd%d%c", fdu, 'a' + i);
912                 }
913 #endif /* DEVFS */
914                 /*
915                  * Export the drive to the devstat interface.
916                  */
917                 devstat_add_entry(&fd->device_stats, "fd", 
918                                   fdu, 512,
919                                   DEVSTAT_NO_ORDERED_TAGS,
920                                   DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_OTHER);
921                 
922         }
923
924         return (1);
925 }
926
927
928
929 #ifdef FDC_YE
930 /*
931  * this is a subset of fdattach() optimized for the Y-E Data
932  * PCMCIA floppy drive.
933  */
934 static int yeattach(struct isa_device *dev)
935 {
936         fdcu_t  fdcu = dev->id_unit;
937         fdc_p   fdc = fdc_data + fdcu;
938         fdsu_t  fdsu = 0;               /* assume 1 drive per YE controller */
939         fdu_t   fdu;
940         fd_p    fd;
941         int     st0, st3, i;
942 #ifdef DEVFS
943         int     mynor;
944         int     typemynor;
945         int     typesize;
946 #endif
947         fdc->fdcu = fdcu;
948         /*
949          * the FDC_PCMCIA flag is used to to indicate special PIO is used
950          * instead of DMA
951          */
952         fdc->flags = FDC_ATTACHED|FDC_PCMCIA;
953         fdc->state = DEVIDLE;
954         /* reset controller, turn motor off, clear fdout mirror reg */
955         outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
956         bufq_init(&fdc->head);
957         /*
958          * assume 2 drives/ "normal" controller
959          */
960         fdu = fdcu * 2;
961         if (fdu >= NFD) {
962                 printf("fdu %d >= NFD\n",fdu);
963                 return(0);
964         };
965         fd = &fd_data[fdu];
966
967         set_motor(fdcu, fdsu, TURNON);
968         DELAY(1000000); /* 1 sec */
969         fdc->fdct = FDC_NE765;
970
971         if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
972                 (st3 & NE7_ST3_T0)) {
973                 /* if at track 0, first seek inwards */
974                 /* seek some steps: */
975                 (void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
976                 DELAY(300000); /* ...wait a moment... */
977                 (void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
978         }
979
980         /* If we're at track 0 first seek inwards. */
981         if ((fd_sense_drive_status(fdc, &st3) == 0) && (st3 & NE7_ST3_T0)) {
982                 /* Seek some steps... */
983                 if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
984                         /* ...wait a moment... */
985                         DELAY(300000);
986                         /* make ctrlr happy: */
987                         (void)fd_sense_int(fdc, 0, 0);
988                 }
989         }
990
991         for(i = 0; i < 2; i++) {
992                 /*
993                  * we must recalibrate twice, just in case the
994                  * heads have been beyond cylinder 76, since most
995                  * FDCs still barf when attempting to recalibrate
996                  * more than 77 steps
997                  */
998                 /* go back to 0: */
999                 if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
1000                         /* a second being enough for full stroke seek*/
1001                         DELAY(i == 0? 1000000: 300000);
1002
1003                         /* anything responding? */
1004                         if (fd_sense_int(fdc, &st0, 0) == 0 &&
1005                                 (st0 & NE7_ST0_EC) == 0)
1006                                 break; /* already probed succesfully */
1007                 }
1008         }
1009
1010         set_motor(fdcu, fdsu, TURNOFF);
1011
1012         if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
1013                 return(0);
1014
1015         fd->track = FD_NO_TRACK;
1016         fd->fdc = fdc;
1017         fd->fdsu = fdsu;
1018         fd->options = 0;
1019         printf("fdc%d: 1.44MB 3.5in PCMCIA\n", fdcu);
1020         fd->type = FD_1440;
1021
1022 #ifdef DEVFS
1023         mynor = fdcu << 6;
1024         fd->bdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_BLK,
1025                 UID_ROOT, GID_OPERATOR, 0640,
1026                 "fd%d", fdu);
1027         fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR,
1028                 UID_ROOT, GID_OPERATOR, 0640,
1029                 "rfd%d", fdu);
1030         /*
1031          * XXX this and the lookup in Fdopen() should be
1032          * data driven.
1033          */
1034         typemynor = mynor | FD_1440;
1035         typesize = fd_types[FD_1440 - 1].size / 2;
1036         /*
1037          * XXX all these conversions give bloated code and
1038          * confusing names.
1039          */
1040         if (typesize == 1476)
1041                 typesize = 1480;
1042         if (typesize == 1722)
1043                 typesize = 1720;
1044         fd->bdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor,
1045                 DV_BLK, UID_ROOT, GID_OPERATOR,
1046                 0640, "fd%d.%d", fdu, typesize);
1047         fd->cdevs[FD_1440] = devfs_add_devswf(&fd_cdevsw, typemynor,
1048                 DV_CHR, UID_ROOT, GID_OPERATOR,
1049                 0640,"rfd%d.%d", fdu, typesize);
1050         for (i = 0; i < MAXPARTITIONS; i++) {
1051                 fd->bdevs[1 + NUMDENS + i] = devfs_makelink(fd->bdevs[0],
1052                         "fd%d%c", fdu, 'a' + i);
1053                 fd->cdevs[1 + NUMDENS + i] = devfs_makelink(fd->cdevs[0],
1054                         "rfd%d%c", fdu, 'a' + i);
1055         }
1056 #endif /* DEVFS */
1057         return (1);
1058 }
1059 #endif
1060
1061 /****************************************************************************/
1062 /*                            motor control stuff                           */
1063 /*              remember to not deselect the drive we're working on         */
1064 /****************************************************************************/
1065 static void
1066 set_motor(fdcu_t fdcu, int fdsu, int turnon)
1067 {
1068         int fdout = fdc_data[fdcu].fdout;
1069         int needspecify = 0;
1070
1071         if(turnon) {
1072                 fdout &= ~FDO_FDSEL;
1073                 fdout |= (FDO_MOEN0 << fdsu) + fdsu;
1074         } else
1075                 fdout &= ~(FDO_MOEN0 << fdsu);
1076
1077         if(!turnon
1078            && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
1079                 /* gonna turn off the last drive, put FDC to bed */
1080                 fdout &= ~ (FDO_FRST|FDO_FDMAEN);
1081         else {
1082                 /* make sure controller is selected and specified */
1083                 if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
1084                         needspecify = 1;
1085                 fdout |= (FDO_FRST|FDO_FDMAEN);
1086         }
1087
1088         outb(fdc_data[fdcu].baseport+FDOUT, fdout);
1089         fdc_data[fdcu].fdout = fdout;
1090         TRACE1("[0x%x->FDOUT]", fdout);
1091
1092         if(needspecify) {
1093                 /*
1094                  * XXX
1095                  * special case: since we have just woken up the FDC
1096                  * from its sleep, we silently assume the command will
1097                  * be accepted, and do not test for a timeout
1098                  */
1099                 (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
1100                              NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
1101                              0);
1102                 if (fdc_data[fdcu].flags & FDC_HAS_FIFO)
1103                         (void) enable_fifo(&fdc_data[fdcu]);
1104         }
1105 }
1106
1107 static void
1108 fd_turnoff(void *arg1)
1109 {
1110         fdu_t fdu = (fdu_t)arg1;
1111         int     s;
1112         fd_p fd = fd_data + fdu;
1113
1114         TRACE1("[fd%d: turnoff]", fdu);
1115
1116         /*
1117          * Don't turn off the motor yet if the drive is active.
1118          * XXX shouldn't even schedule turnoff until drive is inactive
1119          * and nothing is queued on it.
1120          */
1121         if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fdu) {
1122                 fd->toffhandle = timeout(fd_turnoff, arg1, 4 * hz);
1123                 return;
1124         }
1125
1126         s = splbio();
1127         fd->flags &= ~FD_MOTOR;
1128         set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF);
1129         splx(s);
1130 }
1131
1132 static void
1133 fd_motor_on(void *arg1)
1134 {
1135         fdu_t fdu = (fdu_t)arg1;
1136         int     s;
1137
1138         fd_p fd = fd_data + fdu;
1139         s = splbio();
1140         fd->flags &= ~FD_MOTOR_WAIT;
1141         if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
1142         {
1143                 fdintr(fd->fdc->fdcu);
1144         }
1145         splx(s);
1146 }
1147
1148 static void
1149 fd_turnon(fdu_t fdu)
1150 {
1151         fd_p fd = fd_data + fdu;
1152         if(!(fd->flags & FD_MOTOR))
1153         {
1154                 fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
1155                 set_motor(fd->fdc->fdcu, fd->fdsu, TURNON);
1156                 timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
1157         }
1158 }
1159
1160 static void
1161 fdc_reset(fdc_p fdc)
1162 {
1163         fdcu_t fdcu = fdc->fdcu;
1164
1165         /* Try a reset, keep motor on */
1166         outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
1167         TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
1168         DELAY(100);
1169         /* enable FDC, but defer interrupts a moment */
1170         outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN);
1171         TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
1172         DELAY(100);
1173         outb(fdc->baseport + FDOUT, fdc->fdout);
1174         TRACE1("[0x%x->FDOUT]", fdc->fdout);
1175
1176         /* XXX after a reset, silently believe the FDC will accept commands */
1177         (void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
1178                      NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
1179                      0);
1180         if (fdc->flags & FDC_HAS_FIFO)
1181                 (void) enable_fifo(fdc);
1182 }
1183
1184 /****************************************************************************/
1185 /*                             fdc in/out                                   */
1186 /****************************************************************************/
1187 int
1188 in_fdc(fdcu_t fdcu)
1189 {
1190         int baseport = fdc_data[fdcu].baseport;
1191         int i, j = 100000;
1192         while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
1193                 != (NE7_DIO|NE7_RQM) && j-- > 0)
1194                 if (i == NE7_RQM)
1195                         return fdc_err(fdcu, "ready for output in input\n");
1196         if (j <= 0)
1197                 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0);
1198 #ifdef  FDC_DEBUG
1199         i = inb(baseport+FDDATA);
1200         TRACE1("[FDDATA->0x%x]", (unsigned char)i);
1201         return(i);
1202 #else   /* !FDC_DEBUG */
1203         return inb(baseport+FDDATA);
1204 #endif  /* FDC_DEBUG */
1205 }
1206
1207 /*
1208  * fd_in: Like in_fdc, but allows you to see if it worked.
1209  */
1210 static int
1211 fd_in(fdcu_t fdcu, int *ptr)
1212 {
1213         int baseport = fdc_data[fdcu].baseport;
1214         int i, j = 100000;
1215         while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
1216                 != (NE7_DIO|NE7_RQM) && j-- > 0)
1217                 if (i == NE7_RQM)
1218                         return fdc_err(fdcu, "ready for output in input\n");
1219         if (j <= 0)
1220                 return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0);
1221 #ifdef  FDC_DEBUG
1222         i = inb(baseport+FDDATA);
1223         TRACE1("[FDDATA->0x%x]", (unsigned char)i);
1224         *ptr = i;
1225         return 0;
1226 #else   /* !FDC_DEBUG */
1227         i = inb(baseport+FDDATA);
1228         if (ptr)
1229                 *ptr = i;
1230         return 0;
1231 #endif  /* FDC_DEBUG */
1232 }
1233
1234 int
1235 out_fdc(fdcu_t fdcu, int x)
1236 {
1237         int baseport = fdc_data[fdcu].baseport;
1238         int i;
1239
1240         /* Check that the direction bit is set */
1241         i = 100000;
1242         while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
1243         if (i <= 0) return fdc_err(fdcu, "direction bit not set\n");
1244
1245         /* Check that the floppy controller is ready for a command */
1246         i = 100000;
1247         while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
1248         if (i <= 0)
1249                 return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0);
1250
1251         /* Send the command and return */
1252         outb(baseport+FDDATA, x);
1253         TRACE1("[0x%x->FDDATA]", x);
1254         return (0);
1255 }
1256
1257 /****************************************************************************/
1258 /*                           fdopen/fdclose                                 */
1259 /****************************************************************************/
1260 int
1261 Fdopen(dev_t dev, int flags, int mode, struct proc *p)
1262 {
1263         fdu_t fdu = FDUNIT(minor(dev));
1264         int type = FDTYPE(minor(dev));
1265         fdc_p   fdc;
1266
1267 #if NFT > 0
1268         /* check for a tape open */
1269         if (type & F_TAPE_TYPE)
1270                 return(ftopen(dev, flags));
1271 #endif
1272         /* check bounds */
1273         if (fdu >= NFD)
1274                 return(ENXIO);
1275         fdc = fd_data[fdu].fdc;
1276         if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
1277                 return(ENXIO);
1278         if (type > NUMDENS)
1279                 return(ENXIO);
1280         if (type == 0)
1281                 type = fd_data[fdu].type;
1282         else {
1283                 /*
1284                  * For each type of basic drive, make sure we are trying
1285                  * to open a type it can do,
1286                  */
1287                 if (type != fd_data[fdu].type) {
1288                         switch (fd_data[fdu].type) {
1289                         case FD_360:
1290                                 return(ENXIO);
1291                         case FD_720:
1292                                 if (   type != FD_820
1293                                     && type != FD_800
1294                                    )
1295                                         return(ENXIO);
1296                                 break;
1297                         case FD_1200:
1298                                 switch (type) {
1299                                 case FD_1480:
1300                                         type = FD_1480in5_25;
1301                                         break;
1302                                 case FD_1440:
1303                                         type = FD_1440in5_25;
1304                                         break;
1305                                 case FD_820:
1306                                         type = FD_820in5_25;
1307                                         break;
1308                                 case FD_800:
1309                                         type = FD_800in5_25;
1310                                         break;
1311                                 case FD_720:
1312                                         type = FD_720in5_25;
1313                                         break;
1314                                 case FD_360:
1315                                         type = FD_360in5_25;
1316                                         break;
1317                                 default:
1318                                         return(ENXIO);
1319                                 }
1320                                 break;
1321                         case FD_1440:
1322                                 if (   type != FD_1720
1323                                     && type != FD_1480
1324                                     && type != FD_1200
1325                                     && type != FD_820
1326                                     && type != FD_800
1327                                     && type != FD_720
1328                                     )
1329                                         return(ENXIO);
1330                                 break;
1331                         }
1332                 }
1333         }
1334         fd_data[fdu].ft = fd_types + type - 1;
1335         fd_data[fdu].flags |= FD_OPEN;
1336
1337         return 0;
1338 }
1339
1340 int
1341 fdclose(dev_t dev, int flags, int mode, struct proc *p)
1342 {
1343         fdu_t fdu = FDUNIT(minor(dev));
1344
1345 #if NFT > 0
1346         int type = FDTYPE(minor(dev));
1347
1348         if (type & F_TAPE_TYPE)
1349                 return ftclose(dev, flags);
1350 #endif
1351         fd_data[fdu].flags &= ~FD_OPEN;
1352         fd_data[fdu].options &= ~FDOPT_NORETRY;
1353
1354         return(0);
1355 }
1356
1357 static int
1358 fdread(dev_t dev, struct uio *uio, int ioflag)
1359 {
1360         return (physio(fdstrategy, NULL, dev, 1, minphys, uio));
1361 }
1362
1363 static int
1364 fdwrite(dev_t dev, struct uio *uio, int ioflag)
1365 {
1366         return (physio(fdstrategy, NULL, dev, 0, minphys, uio));
1367 }
1368
1369
1370 /****************************************************************************/
1371 /*                               fdstrategy                                 */
1372 /****************************************************************************/
1373 void
1374 fdstrategy(struct buf *bp)
1375 {
1376         unsigned nblocks, blknum, cando;
1377         int     s;
1378         fdcu_t  fdcu;
1379         fdu_t   fdu;
1380         fdc_p   fdc;
1381         fd_p    fd;
1382         size_t  fdblk;
1383
1384         fdu = FDUNIT(minor(bp->b_dev));
1385         fd = &fd_data[fdu];
1386         fdc = fd->fdc;
1387         fdcu = fdc->fdcu;
1388 #ifdef FDC_YE
1389         if (fd->type == NO_TYPE) {
1390                 bp->b_error = ENXIO;
1391                 bp->b_flags |= B_ERROR;
1392                 /*
1393                  * I _refuse_ to use a goto
1394                  */
1395                 biodone(bp);
1396                 return;
1397         };
1398 #endif
1399
1400 #if NFT > 0
1401         if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) {
1402                 /* ft tapes do not (yet) support strategy i/o */
1403                 bp->b_error = ENODEV;
1404                 bp->b_flags |= B_ERROR;
1405                 goto bad;
1406         }
1407         /* check for controller already busy with tape */
1408         if (fdc->flags & FDC_TAPE_BUSY) {
1409                 bp->b_error = EBUSY;
1410                 bp->b_flags |= B_ERROR;
1411                 goto bad;
1412         }
1413 #endif
1414         fdblk = 128 << (fd->ft->secsize);
1415         if (!(bp->b_flags & B_FORMAT)) {
1416                 if ((fdu >= NFD) || (bp->b_blkno < 0)) {
1417                         printf(
1418                 "fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
1419                                fdu, (u_long)bp->b_blkno, bp->b_bcount);
1420                         bp->b_error = EINVAL;
1421                         bp->b_flags |= B_ERROR;
1422                         goto bad;
1423                 }
1424                 if ((bp->b_bcount % fdblk) != 0) {
1425                         bp->b_error = EINVAL;
1426                         bp->b_flags |= B_ERROR;
1427                         goto bad;
1428                 }
1429         }
1430
1431         /*
1432          * Set up block calculations.
1433          */
1434         if (bp->b_blkno > 20000000) {
1435                 /*
1436                  * Reject unreasonably high block number, prevent the
1437                  * multiplication below from overflowing.
1438                  */
1439                 bp->b_error = EINVAL;
1440                 bp->b_flags |= B_ERROR;
1441                 goto bad;
1442         }
1443         blknum = (unsigned) bp->b_blkno * DEV_BSIZE/fdblk;
1444         nblocks = fd->ft->size;
1445         bp->b_resid = 0;
1446         if (blknum + (bp->b_bcount / fdblk) > nblocks) {
1447                 if (blknum <= nblocks) {
1448                         cando = (nblocks - blknum) * fdblk;
1449                         bp->b_resid = bp->b_bcount - cando;
1450                         if (cando == 0)
1451                                 goto bad;       /* not actually bad but EOF */
1452                 } else {
1453                         bp->b_error = EINVAL;
1454                         bp->b_flags |= B_ERROR;
1455                         goto bad;
1456                 }
1457         }
1458         bp->b_pblkno = bp->b_blkno;
1459         s = splbio();
1460         bufqdisksort(&fdc->head, bp);
1461         untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle); /* a good idea */
1462
1463         /* Tell devstat we are starting on the transaction */
1464         devstat_start_transaction(&fd->device_stats);
1465
1466         fdstart(fdcu);
1467         splx(s);
1468         return;
1469
1470 bad:
1471         biodone(bp);
1472 }
1473
1474 /***************************************************************\
1475 *                               fdstart                         *
1476 * We have just queued something.. if the controller is not busy *
1477 * then simulate the case where it has just finished a command   *
1478 * So that it (the interrupt routine) looks on the queue for more*
1479 * work to do and picks up what we just added.                   *
1480 * If the controller is already busy, we need do nothing, as it  *
1481 * will pick up our work when the present work completes         *
1482 \***************************************************************/
1483 static void
1484 fdstart(fdcu_t fdcu)
1485 {
1486         int s;
1487
1488         s = splbio();
1489         if(fdc_data[fdcu].state == DEVIDLE)
1490         {
1491                 fdintr(fdcu);
1492         }
1493         splx(s);
1494 }
1495
1496 static void
1497 fd_iotimeout(void *arg1)
1498 {
1499         fdc_p fdc;
1500         fdcu_t fdcu;
1501         int s;
1502
1503         fdcu = (fdcu_t)arg1;
1504         fdc = fdc_data + fdcu;
1505         TRACE1("fd%d[fd_iotimeout()]", fdc->fdu);
1506
1507         /*
1508          * Due to IBM's brain-dead design, the FDC has a faked ready
1509          * signal, hardwired to ready == true. Thus, any command
1510          * issued if there's no diskette in the drive will _never_
1511          * complete, and must be aborted by resetting the FDC.
1512          * Many thanks, Big Blue!
1513          * The FDC must not be reset directly, since that would
1514          * interfere with the state machine.  Instead, pretend that
1515          * the command completed but was invalid.  The state machine
1516          * will reset the FDC and retry once.
1517          */
1518         s = splbio();
1519         fdc->status[0] = NE7_ST0_IC_IV;
1520         fdc->flags &= ~FDC_STAT_VALID;
1521         fdc->state = IOTIMEDOUT;
1522         fdintr(fdcu);
1523         splx(s);
1524 }
1525
1526 /* just ensure it has the right spl */
1527 static void
1528 fd_pseudointr(void *arg1)
1529 {
1530         fdcu_t fdcu = (fdcu_t)arg1;
1531         int     s;
1532
1533         s = splbio();
1534         fdintr(fdcu);
1535         splx(s);
1536 }
1537
1538 /***********************************************************************\
1539 *                                 fdintr                                *
1540 * keep calling the state machine until it returns a 0                   *
1541 * ALWAYS called at SPLBIO                                               *
1542 \***********************************************************************/
1543 static void
1544 fdintr(fdcu_t fdcu)
1545 {
1546         fdc_p fdc = fdc_data + fdcu;
1547 #if NFT > 0
1548         fdu_t fdu = fdc->fdu;
1549
1550         if (fdc->flags & FDC_TAPE_BUSY)
1551                 (ftintr(fdu));
1552         else
1553 #endif
1554                 while(fdstate(fdcu, fdc))
1555                         ;
1556 }
1557
1558 #ifdef FDC_YE
1559 /*
1560  * magic pseudo-DMA initialization for YE FDC. Sets count and
1561  * direction
1562  */
1563 #define SET_BCDR(wr,cnt,port) outb(port,(((cnt)-1) & 0xff)); \
1564         outb(port+1,((wr ? 0x80 : 0) | ((((cnt)-1) >> 8) & 0x7f)))
1565
1566 /*
1567  * fdcpio(): perform programmed IO read/write for YE PCMCIA floppy
1568  */
1569 static int fdcpio(fdcu_t fdcu, long flags, caddr_t addr, u_int count)
1570 {
1571         u_char *cptr = (u_char *)addr;
1572         fdc_p fdc = &fdc_data[fdcu];
1573         int io = fdc->baseport;
1574
1575         if (flags & B_READ) {
1576                 if (fdc->state != PIOREAD) {
1577                         fdc->state = PIOREAD;
1578                         return(0);
1579                 };
1580                 SET_BCDR(0,count,io);
1581                 insb(io+FDC_YE_DATAPORT,cptr,count);
1582         } else {
1583                 outsb(io+FDC_YE_DATAPORT,cptr,count);
1584                 SET_BCDR(0,count,io);
1585         };
1586         return(1);
1587 }
1588 #endif /* FDC_YE */
1589
1590 /***********************************************************************\
1591 * The controller state machine.                                         *
1592 * if it returns a non zero value, it should be called again immediatly  *
1593 \***********************************************************************/
1594 static int
1595 fdstate(fdcu_t fdcu, fdc_p fdc)
1596 {
1597         int read, format, head, i, sec = 0, sectrac, st0, cyl, st3;
1598         unsigned blknum = 0, b_cylinder = 0;
1599         fdu_t fdu = fdc->fdu;
1600         fd_p fd;
1601         register struct buf *bp;
1602         struct fd_formb *finfo = NULL;
1603         size_t fdblk;
1604
1605         bp = bufq_first(&fdc->head);
1606         if(!bp) {
1607                 /***********************************************\
1608                 * nothing left for this controller to do        *
1609                 * Force into the IDLE state,                    *
1610                 \***********************************************/
1611                 fdc->state = DEVIDLE;
1612                 if(fdc->fd)
1613                 {
1614                         printf("fd%d: unexpected valid fd pointer\n",
1615                                fdc->fdu);
1616                         fdc->fd = (fd_p) 0;
1617                         fdc->fdu = -1;
1618                 }
1619                 TRACE1("[fdc%d IDLE]", fdcu);
1620                 return(0);
1621         }
1622         fdu = FDUNIT(minor(bp->b_dev));
1623         fd = fd_data + fdu;
1624         fdblk = 128 << fd->ft->secsize;
1625         if (fdc->fd && (fd != fdc->fd))
1626         {
1627                 printf("fd%d: confused fd pointers\n", fdu);
1628         }
1629         read = bp->b_flags & B_READ;
1630         format = bp->b_flags & B_FORMAT;
1631         if(format) {
1632                 finfo = (struct fd_formb *)bp->b_data;
1633                 fd->skip = (char *)&(finfo->fd_formb_cylno(0))
1634                         - (char *)finfo;
1635         }
1636         if (fdc->state == DOSEEK || fdc->state == SEEKCOMPLETE) {
1637                 blknum = (unsigned) bp->b_pblkno * DEV_BSIZE/fdblk +
1638                         fd->skip/fdblk;
1639                 b_cylinder = blknum / (fd->ft->sectrac * fd->ft->heads);
1640         }
1641         TRACE1("fd%d", fdu);
1642         TRACE1("[%s]", fdstates[fdc->state]);
1643         TRACE1("(0x%x)", fd->flags);
1644         untimeout(fd_turnoff, (caddr_t)fdu, fd->toffhandle);
1645         fd->toffhandle = timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
1646         switch (fdc->state)
1647         {
1648         case DEVIDLE:
1649         case FINDWORK:  /* we have found new work */
1650                 fdc->retry = 0;
1651                 fd->skip = 0;
1652                 fdc->fd = fd;
1653                 fdc->fdu = fdu;
1654                 outb(fdc->baseport+FDCTL, fd->ft->trans);
1655                 TRACE1("[0x%x->FDCTL]", fd->ft->trans);
1656                 /*******************************************************\
1657                 * If the next drive has a motor startup pending, then   *
1658                 * it will start up in its own good time         *
1659                 \*******************************************************/
1660                 if(fd->flags & FD_MOTOR_WAIT)
1661                 {
1662                         fdc->state = MOTORWAIT;
1663                         return(0); /* come back later */
1664                 }
1665                 /*******************************************************\
1666                 * Maybe if it's not starting, it SHOULD be starting     *
1667                 \*******************************************************/
1668                 if (!(fd->flags & FD_MOTOR))
1669                 {
1670                         fdc->state = MOTORWAIT;
1671                         fd_turnon(fdu);
1672                         return(0);
1673                 }
1674                 else    /* at least make sure we are selected */
1675                 {
1676                         set_motor(fdcu, fd->fdsu, TURNON);
1677                 }
1678                 if (fdc->flags & FDC_NEEDS_RESET) {
1679                         fdc->state = RESETCTLR;
1680                         fdc->flags &= ~FDC_NEEDS_RESET;
1681                 } else
1682                         fdc->state = DOSEEK;
1683                 break;
1684         case DOSEEK:
1685                 if (b_cylinder == (unsigned)fd->track)
1686                 {
1687                         fdc->state = SEEKCOMPLETE;
1688                         break;
1689                 }
1690                 if (fd_cmd(fdcu, 3, NE7CMD_SEEK,
1691                            fd->fdsu, b_cylinder * fd->ft->steptrac,
1692                            0))
1693                 {
1694                         /*
1695                          * seek command not accepted, looks like
1696                          * the FDC went off to the Saints...
1697                          */
1698                         fdc->retry = 6; /* try a reset */
1699                         return(retrier(fdcu));
1700                 }
1701                 fd->track = FD_NO_TRACK;
1702                 fdc->state = SEEKWAIT;
1703                 return(0);      /* will return later */
1704         case SEEKWAIT:
1705                 /* allow heads to settle */
1706                 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16);
1707                 fdc->state = SEEKCOMPLETE;
1708                 return(0);      /* will return later */
1709         case SEEKCOMPLETE : /* SEEK DONE, START DMA */
1710                 /* Make sure seek really happened*/
1711                 if(fd->track == FD_NO_TRACK)
1712                 {
1713                         int descyl = b_cylinder * fd->ft->steptrac;
1714                         do {
1715                                 /*
1716                                  * This might be a "ready changed" interrupt,
1717                                  * which cannot really happen since the
1718                                  * RDY pin is hardwired to + 5 volts.  This
1719                                  * generally indicates a "bouncing" intr
1720                                  * line, so do one of the following:
1721                                  *
1722                                  * When running on an enhanced FDC that is
1723                                  * known to not go stuck after responding
1724                                  * with INVALID, fetch all interrupt states
1725                                  * until seeing either an INVALID or a
1726                                  * real interrupt condition.
1727                                  *
1728                                  * When running on a dumb old NE765, give
1729                                  * up immediately.  The controller will
1730                                  * provide up to four dummy RC interrupt
1731                                  * conditions right after reset (for the
1732                                  * corresponding four drives), so this is
1733                                  * our only chance to get notice that it
1734                                  * was not the FDC that caused the interrupt.
1735                                  */
1736                                 if (fd_sense_int(fdc, &st0, &cyl)
1737                                     == FD_NOT_VALID)
1738                                         return 0;
1739                                 if(fdc->fdct == FDC_NE765
1740                                    && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
1741                                         return 0; /* hope for a real intr */
1742                         } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
1743
1744                         if (0 == descyl)
1745                         {
1746                                 int failed = 0;
1747                                 /*
1748                                  * seek to cyl 0 requested; make sure we are
1749                                  * really there
1750                                  */
1751                                 if (fd_sense_drive_status(fdc, &st3))
1752                                         failed = 1;
1753                                 if ((st3 & NE7_ST3_T0) == 0) {
1754                                         printf(
1755                 "fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
1756                                                fdu, st3, NE7_ST3BITS);
1757                                         failed = 1;
1758                                 }
1759
1760                                 if (failed)
1761                                 {
1762                                         if(fdc->retry < 3)
1763                                                 fdc->retry = 3;
1764                                         return(retrier(fdcu));
1765                                 }
1766                         }
1767
1768                         if (cyl != descyl)
1769                         {
1770                                 printf(
1771                 "fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
1772                                        fdu, descyl, cyl, st0);
1773                                 if (fdc->retry < 3)
1774                                         fdc->retry = 3;
1775                                 return(retrier(fdcu));
1776                         }
1777                 }
1778
1779                 fd->track = b_cylinder;
1780 #ifdef FDC_YE
1781                 if (!(fdc->flags & FDC_PCMCIA))
1782 #endif
1783                         isa_dmastart(bp->b_flags, bp->b_data+fd->skip,
1784                                 format ? bp->b_bcount : fdblk, fdc->dmachan);
1785                 sectrac = fd->ft->sectrac;
1786                 sec = blknum %  (sectrac * fd->ft->heads);
1787                 head = sec / sectrac;
1788                 sec = sec % sectrac + 1;
1789                 fd->hddrv = ((head&1)<<2)+fdu;
1790
1791                 if(format || !read)
1792                 {
1793                         /* make sure the drive is writable */
1794                         if(fd_sense_drive_status(fdc, &st3) != 0)
1795                         {
1796                                 /* stuck controller? */
1797                                 isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
1798                                             format ? bp->b_bcount : fdblk,
1799                                             fdc->dmachan);
1800                                 fdc->retry = 6; /* reset the beast */
1801                                 return(retrier(fdcu));
1802                         }
1803                         if(st3 & NE7_ST3_WP)
1804                         {
1805                                 /*
1806                                  * XXX YES! this is ugly.
1807                                  * in order to force the current operation
1808                                  * to fail, we will have to fake an FDC
1809                                  * error - all error handling is done
1810                                  * by the retrier()
1811                                  */
1812                                 fdc->status[0] = NE7_ST0_IC_AT;
1813                                 fdc->status[1] = NE7_ST1_NW;
1814                                 fdc->status[2] = 0;
1815                                 fdc->status[3] = fd->track;
1816                                 fdc->status[4] = head;
1817                                 fdc->status[5] = sec;
1818                                 fdc->retry = 8; /* break out immediately */
1819                                 fdc->state = IOTIMEDOUT; /* not really... */
1820                                 return (1);
1821                         }
1822                 }
1823
1824                 if(format)
1825                 {
1826 #ifdef FDC_YE
1827                         if (fdc->flags & FDC_PCMCIA)
1828                                 (void)fdcpio(fdcu,bp->b_flags,
1829                                         bp->b_data+fd->skip,
1830                                         bp->b_bcount);
1831 #endif
1832                         /* formatting */
1833                         if(fd_cmd(fdcu, 6,
1834                                   NE7CMD_FORMAT,
1835                                   head << 2 | fdu,
1836                                   finfo->fd_formb_secshift,
1837                                   finfo->fd_formb_nsecs,
1838                                   finfo->fd_formb_gaplen,
1839                                   finfo->fd_formb_fillbyte,
1840                                   0))
1841                         {
1842                                 /* controller fell over */
1843                                 isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
1844                                             format ? bp->b_bcount : fdblk,
1845                                             fdc->dmachan);
1846                                 fdc->retry = 6;
1847                                 return(retrier(fdcu));
1848                         }
1849                 }
1850                 else
1851                 {
1852 #ifdef FDC_YE
1853                         if (fdc->flags & FDC_PCMCIA) {
1854                                 /*
1855                                  * this seems to be necessary even when
1856                                  * reading data
1857                                  */
1858                                 SET_BCDR(1,fdblk,fdc->baseport);
1859
1860                                 /*
1861                                  * perform the write pseudo-DMA before
1862                                  * the WRITE command is sent
1863                                  */
1864                                 if (!read)
1865                                         (void)fdcpio(fdcu,bp->b_flags,
1866                                             bp->b_data+fd->skip,
1867                                             fdblk);
1868                         }
1869 #endif
1870                         if (fd_cmd(fdcu, 9,
1871                                    (read ? NE7CMD_READ : NE7CMD_WRITE),
1872                                    head << 2 | fdu,  /* head & unit */
1873                                    fd->track,        /* track */
1874                                    head,
1875                                    sec,              /* sector + 1 */
1876                                    fd->ft->secsize,  /* sector size */
1877                                    sectrac,          /* sectors/track */
1878                                    fd->ft->gap,      /* gap size */
1879                                    fd->ft->datalen,  /* data length */
1880                                    0))
1881                         {
1882                                 /* the beast is sleeping again */
1883                                 isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
1884                                             format ? bp->b_bcount : fdblk,
1885                                             fdc->dmachan);
1886                                 fdc->retry = 6;
1887                                 return(retrier(fdcu));
1888                         }
1889                 }
1890 #ifdef FDC_YE
1891                 if (fdc->flags & FDC_PCMCIA)
1892                         /*
1893                          * if this is a read, then simply await interrupt
1894                          * before performing PIO
1895                          */
1896                         if (read && !fdcpio(fdcu,bp->b_flags,
1897                             bp->b_data+fd->skip,fdblk)) {
1898                                 fd->tohandle = timeout(fd_iotimeout, 
1899                                         (caddr_t)fdcu, hz);
1900                                 return(0);      /* will return later */
1901                         };
1902
1903                 /*
1904                  * write (or format) operation will fall through and
1905                  * await completion interrupt
1906                  */
1907 #endif
1908                 fdc->state = IOCOMPLETE;
1909                 fd->tohandle = timeout(fd_iotimeout, (caddr_t)fdcu, hz);
1910                 return(0);      /* will return later */
1911 #ifdef FDC_YE
1912         case PIOREAD:
1913                 /* 
1914                  * actually perform the PIO read.  The IOCOMPLETE case
1915                  * removes the timeout for us.  
1916                  */
1917                 (void)fdcpio(fdcu,bp->b_flags,bp->b_data+fd->skip,fdblk);
1918                 fdc->state = IOCOMPLETE;
1919                 /* FALLTHROUGH */
1920 #endif
1921         case IOCOMPLETE: /* IO DONE, post-analyze */
1922                 untimeout(fd_iotimeout, (caddr_t)fdcu, fd->tohandle);
1923
1924                 if (fd_read_status(fdc, fd->fdsu))
1925                 {
1926                         isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
1927                                     format ? bp->b_bcount : fdblk,
1928                                     fdc->dmachan);
1929                         if (fdc->retry < 6)
1930                                 fdc->retry = 6; /* force a reset */
1931                         return retrier(fdcu);
1932                 }
1933
1934                 fdc->state = IOTIMEDOUT;
1935
1936                 /* FALLTHROUGH */
1937
1938         case IOTIMEDOUT:
1939 #ifdef FDC_YE
1940                 if (!(fdc->flags & FDC_PCMCIA))
1941 #endif
1942                         isa_dmadone(bp->b_flags, bp->b_data + fd->skip,
1943                                 format ? bp->b_bcount : fdblk, fdc->dmachan);
1944                 if (fdc->status[0] & NE7_ST0_IC)
1945                 {
1946                         if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
1947                             && fdc->status[1] & NE7_ST1_OR) {
1948                                 /*
1949                                  * DMA overrun. Someone hogged the bus
1950                                  * and didn't release it in time for the
1951                                  * next FDC transfer.
1952                                  * Just restart it, don't increment retry
1953                                  * count. (vak)
1954                                  */
1955                                 fdc->state = SEEKCOMPLETE;
1956                                 return (1);
1957                         }
1958                         else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
1959                                 && fdc->retry < 6)
1960                                 fdc->retry = 6; /* force a reset */
1961                         else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
1962                                 && fdc->status[2] & NE7_ST2_WC
1963                                 && fdc->retry < 3)
1964                                 fdc->retry = 3; /* force recalibrate */
1965                         return(retrier(fdcu));
1966                 }
1967                 /* All OK */
1968                 fd->skip += fdblk;
1969                 if (!format && fd->skip < bp->b_bcount - bp->b_resid)
1970                 {
1971                         /* set up next transfer */
1972                         fdc->state = DOSEEK;
1973                 }
1974                 else
1975                 {
1976                         /* ALL DONE */
1977                         fd->skip = 0;
1978                         bufq_remove(&fdc->head, bp);
1979                         /* Tell devstat we have finished with the transaction */
1980                         devstat_end_transaction(&fd->device_stats,
1981                                                 bp->b_bcount - bp->b_resid,
1982                                                 DEVSTAT_TAG_NONE,
1983                                                 (bp->b_flags & B_READ) ?
1984                                                 DEVSTAT_READ : DEVSTAT_WRITE);
1985                         biodone(bp);
1986                         fdc->fd = (fd_p) 0;
1987                         fdc->fdu = -1;
1988                         fdc->state = FINDWORK;
1989                 }
1990                 return(1);
1991         case RESETCTLR:
1992                 fdc_reset(fdc);
1993                 fdc->retry++;
1994                 fdc->state = RESETCOMPLETE;
1995                 return (0);
1996         case RESETCOMPLETE:
1997                 /*
1998                  * Discard all the results from the reset so that they
1999                  * can't cause an unexpected interrupt later.
2000                  */
2001                 for (i = 0; i < 4; i++)
2002                         (void)fd_sense_int(fdc, &st0, &cyl);
2003                 fdc->state = STARTRECAL;
2004                 /* Fall through. */
2005         case STARTRECAL:
2006                 if(fd_cmd(fdcu,
2007                           2, NE7CMD_RECAL, fdu,
2008                           0)) /* Recalibrate Function */
2009                 {
2010                         /* arrgl */
2011                         fdc->retry = 6;
2012                         return(retrier(fdcu));
2013                 }
2014                 fdc->state = RECALWAIT;
2015                 return(0);      /* will return later */
2016         case RECALWAIT:
2017                 /* allow heads to settle */
2018                 timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8);
2019                 fdc->state = RECALCOMPLETE;
2020                 return(0);      /* will return later */
2021         case RECALCOMPLETE:
2022                 do {
2023                         /*
2024                          * See SEEKCOMPLETE for a comment on this:
2025                          */
2026                         if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
2027                                 return 0;
2028                         if(fdc->fdct == FDC_NE765
2029                            && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
2030                                 return 0; /* hope for a real intr */
2031                 } while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
2032                 if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
2033                 {
2034                         if(fdc->retry > 3)
2035                                 /*
2036                                  * a recalibrate from beyond cylinder 77
2037                                  * will "fail" due to the FDC limitations;
2038                                  * since people used to complain much about
2039                                  * the failure message, try not logging
2040                                  * this one if it seems to be the first
2041                                  * time in a line
2042                                  */
2043                                 printf("fd%d: recal failed ST0 %b cyl %d\n",
2044                                        fdu, st0, NE7_ST0BITS, cyl);
2045                         if(fdc->retry < 3) fdc->retry = 3;
2046                         return(retrier(fdcu));
2047                 }
2048                 fd->track = 0;
2049                 /* Seek (probably) necessary */
2050                 fdc->state = DOSEEK;
2051                 return(1);      /* will return immediatly */
2052         case MOTORWAIT:
2053                 if(fd->flags & FD_MOTOR_WAIT)
2054                 {
2055                         return(0); /* time's not up yet */
2056                 }
2057                 if (fdc->flags & FDC_NEEDS_RESET) {
2058                         fdc->state = RESETCTLR;
2059                         fdc->flags &= ~FDC_NEEDS_RESET;
2060                 } else {
2061                         /*
2062                          * If all motors were off, then the controller was
2063                          * reset, so it has lost track of the current
2064                          * cylinder.  Recalibrate to handle this case.
2065                          */
2066                         fdc->state = STARTRECAL;
2067                 }
2068                 return(1);      /* will return immediatly */
2069         default:
2070                 printf("fdc%d: Unexpected FD int->", fdcu);
2071                 if (fd_read_status(fdc, fd->fdsu) == 0)
2072                         printf("FDC status :%x %x %x %x %x %x %x   ",
2073                                fdc->status[0],
2074                                fdc->status[1],
2075                                fdc->status[2],
2076                                fdc->status[3],
2077                                fdc->status[4],
2078                                fdc->status[5],
2079                                fdc->status[6] );
2080                 else
2081                         printf("No status available   ");
2082                 if (fd_sense_int(fdc, &st0, &cyl) != 0)
2083                 {
2084                         printf("[controller is dead now]\n");
2085                         return(0);
2086                 }
2087                 printf("ST0 = %x, PCN = %x\n", st0, cyl);
2088                 return(0);
2089         }
2090         /*XXX confusing: some branches return immediately, others end up here*/
2091         return(1); /* Come back immediatly to new state */
2092 }
2093
2094 static int
2095 retrier(fdcu)
2096         fdcu_t fdcu;
2097 {
2098         fdc_p fdc = fdc_data + fdcu;
2099         register struct buf *bp;
2100
2101         bp = bufq_first(&fdc->head);
2102
2103         if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY)
2104                 goto fail;
2105         switch(fdc->retry)
2106         {
2107         case 0: case 1: case 2:
2108                 fdc->state = SEEKCOMPLETE;
2109                 break;
2110         case 3: case 4: case 5:
2111                 fdc->state = STARTRECAL;
2112                 break;
2113         case 6:
2114                 fdc->state = RESETCTLR;
2115                 break;
2116         case 7:
2117                 break;
2118         default:
2119         fail:
2120                 {
2121                         dev_t sav_b_dev = bp->b_dev;
2122                         /* Trick diskerr */
2123                         bp->b_dev = makedev(major(bp->b_dev),
2124                                     (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
2125                         diskerr(bp, "fd", "hard error", LOG_PRINTF,
2126                                 fdc->fd->skip / DEV_BSIZE,
2127                                 (struct disklabel *)NULL);
2128                         bp->b_dev = sav_b_dev;
2129                         if (fdc->flags & FDC_STAT_VALID)
2130                         {
2131                                 printf(
2132                         " (ST0 %b ST1 %b ST2 %b cyl %u hd %u sec %u)\n",
2133                                        fdc->status[0], NE7_ST0BITS,
2134                                        fdc->status[1], NE7_ST1BITS,
2135                                        fdc->status[2], NE7_ST2BITS,
2136                                        fdc->status[3], fdc->status[4],
2137                                        fdc->status[5]);
2138                         }
2139                         else
2140                                 printf(" (No status)\n");
2141                 }
2142                 bp->b_flags |= B_ERROR;
2143                 bp->b_error = EIO;
2144                 bp->b_resid += bp->b_bcount - fdc->fd->skip;
2145                 bufq_remove(&fdc->head, bp);
2146         
2147                 /* Tell devstat we have finished with the transaction */
2148                 devstat_end_transaction(&fdc->fd->device_stats,
2149                                         bp->b_bcount - bp->b_resid,
2150                                         DEVSTAT_TAG_NONE,
2151                                         (bp->b_flags & B_READ) ? DEVSTAT_READ :
2152                                                                  DEVSTAT_WRITE);
2153                 fdc->fd->skip = 0;
2154                 biodone(bp);
2155                 fdc->state = FINDWORK;
2156                 fdc->flags |= FDC_NEEDS_RESET;
2157                 fdc->fd = (fd_p) 0;
2158                 fdc->fdu = -1;
2159                 return(1);
2160         }
2161         fdc->retry++;
2162         return(1);
2163 }
2164
2165 static int
2166 fdformat(dev, finfo, p)
2167         dev_t dev;
2168         struct fd_formb *finfo;
2169         struct proc *p;
2170 {
2171         fdu_t   fdu;
2172         fd_p    fd;
2173
2174         struct buf *bp;
2175         int rv = 0, s;
2176         size_t fdblk;
2177
2178         fdu     = FDUNIT(minor(dev));
2179         fd      = &fd_data[fdu];
2180         fdblk = 128 << fd->ft->secsize;
2181
2182         /* set up a buffer header for fdstrategy() */
2183         bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
2184         if(bp == 0)
2185                 return ENOBUFS;
2186         /*
2187          * keep the process from being swapped
2188          */
2189         p->p_flag |= P_PHYSIO;
2190         bzero((void *)bp, sizeof(struct buf));
2191         bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
2192         bp->b_proc = p;
2193
2194         /*
2195          * calculate a fake blkno, so fdstrategy() would initiate a
2196          * seek to the requested cylinder
2197          */
2198         bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
2199                 + finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
2200
2201         bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
2202         bp->b_data = (caddr_t)finfo;
2203
2204         /* now do the format */
2205         bp->b_dev = dev;
2206         fdstrategy(bp);
2207
2208         /* ...and wait for it to complete */
2209         s = splbio();
2210         while(!(bp->b_flags & B_DONE))
2211         {
2212                 rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
2213                 if(rv == EWOULDBLOCK)
2214                         break;
2215         }
2216         splx(s);
2217
2218         if(rv == EWOULDBLOCK) {
2219                 /* timed out */
2220                 rv = EIO;
2221                 biodone(bp);
2222         }
2223         if(bp->b_flags & B_ERROR)
2224                 rv = bp->b_error;
2225         /*
2226          * allow the process to be swapped
2227          */
2228         p->p_flag &= ~P_PHYSIO;
2229         free(bp, M_TEMP);
2230         return rv;
2231 }
2232
2233 /*
2234  * TODO: don't allocate buffer on stack.
2235  */
2236
2237 static int
2238 fdioctl(dev, cmd, addr, flag, p)
2239         dev_t dev;
2240         u_long cmd;
2241         caddr_t addr;
2242         int flag;
2243         struct proc *p;
2244 {
2245         fdu_t   fdu = FDUNIT(minor(dev));
2246         fd_p    fd = &fd_data[fdu];
2247         size_t fdblk;
2248
2249         struct fd_type *fdt;
2250         struct disklabel *dl;
2251         char buffer[DEV_BSIZE];
2252         int error = 0;
2253
2254 #if NFT > 0
2255         int type = FDTYPE(minor(dev));
2256
2257         /* check for a tape ioctl */
2258         if (type & F_TAPE_TYPE)
2259                 return ftioctl(dev, cmd, addr, flag, p);
2260 #endif
2261
2262         fdblk = 128 << fd->ft->secsize;
2263
2264         switch (cmd)
2265         {
2266         case DIOCGDINFO:
2267                 bzero(buffer, sizeof (buffer));
2268                 dl = (struct disklabel *)buffer;
2269                 dl->d_secsize = fdblk;
2270                 fdt = fd_data[FDUNIT(minor(dev))].ft;
2271                 dl->d_secpercyl = fdt->size / fdt->tracks;
2272                 dl->d_type = DTYPE_FLOPPY;
2273
2274                 if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl)
2275                     == NULL)
2276                         error = 0;
2277                 else
2278                         error = EINVAL;
2279
2280                 *(struct disklabel *)addr = *dl;
2281                 break;
2282
2283         case DIOCSDINFO:
2284                 if ((flag & FWRITE) == 0)
2285                         error = EBADF;
2286                 break;
2287
2288         case DIOCWLABEL:
2289                 if ((flag & FWRITE) == 0)
2290                         error = EBADF;
2291                 break;
2292
2293         case DIOCWDINFO:
2294                 if ((flag & FWRITE) == 0)
2295                 {
2296                         error = EBADF;
2297                         break;
2298                 }
2299
2300                 dl = (struct disklabel *)addr;
2301
2302                 if ((error = setdisklabel((struct disklabel *)buffer, dl,
2303                                           (u_long)0)) != 0)
2304                         break;
2305
2306                 error = writedisklabel(dev, fdstrategy,
2307                                        (struct disklabel *)buffer);
2308                 break;
2309         case FD_FORM:
2310                 if((flag & FWRITE) == 0)
2311                         error = EBADF;  /* must be opened for writing */
2312                 else if(((struct fd_formb *)addr)->format_version !=
2313                         FD_FORMAT_VERSION)
2314                         error = EINVAL; /* wrong version of formatting prog */
2315                 else
2316                         error = fdformat(dev, (struct fd_formb *)addr, p);
2317                 break;
2318
2319         case FD_GTYPE:                  /* get drive type */
2320                 *(struct fd_type *)addr = *fd->ft;
2321                 break;
2322
2323         case FD_STYPE:                  /* set drive type */
2324                 /* this is considered harmful; only allow for superuser */
2325                 if(suser(p->p_ucred, &p->p_acflag) != 0)
2326                         return EPERM;
2327                 *fd->ft = *(struct fd_type *)addr;
2328                 break;
2329
2330         case FD_GOPTS:                  /* get drive options */
2331                 *(int *)addr = fd->options;
2332                 break;
2333
2334         case FD_SOPTS:                  /* set drive options */
2335                 fd->options = *(int *)addr;
2336                 break;
2337
2338         default:
2339                 error = ENOTTY;
2340                 break;
2341         }
2342         return (error);
2343 }
2344
2345
2346 static fd_devsw_installed = 0;
2347
2348 static void     fd_drvinit(void *notused )
2349 {
2350
2351         if( ! fd_devsw_installed ) {
2352                 cdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &fd_cdevsw);
2353                 fd_devsw_installed = 1;
2354         }
2355 }
2356
2357 SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL)
2358
2359
2360 #endif
2361
2362 /*
2363  * Hello emacs, these are the
2364  * Local Variables:
2365  *  c-indent-level:               8
2366  *  c-continued-statement-offset: 8
2367  *  c-continued-brace-offset:     0
2368  *  c-brace-offset:              -8
2369  *  c-brace-imaginary-offset:     0
2370  *  c-argdecl-indent:             8
2371  *  c-label-offset:              -8
2372  *  c++-hanging-braces:           1
2373  *  c++-access-specifier-offset: -8
2374  *  c++-empty-arglist-indent:     8
2375  *  c++-friend-offset:            0
2376  * End:
2377  */