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