fdc.c revision 15108
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.84 1996/04/02 04:51:04 scrappy Exp $
47 *
48 */
49
50#include "ft.h"
51#if NFT < 1
52#undef NFDC
53#endif
54#include "fd.h"
55
56#if NFDC > 0
57
58#include <sys/param.h>
59#include <sys/systm.h>
60#include <sys/kernel.h>
61#include <sys/conf.h>
62#include <sys/file.h>
63#include <sys/ioctl.h>
64#include <machine/clock.h>
65#include <machine/ioctl_fd.h>
66#include <sys/disklabel.h>
67#include <sys/diskslice.h>
68#include <machine/cpu.h>
69#include <sys/buf.h>
70#include <sys/uio.h>
71#include <sys/malloc.h>
72#include <sys/proc.h>
73#include <sys/syslog.h>
74#include <sys/devconf.h>
75#include <sys/dkstat.h>
76#include <i386/isa/isa.h>
77#include <i386/isa/isa_device.h>
78#include <i386/isa/fdreg.h>
79#include <i386/isa/fdc.h>
80#include <i386/isa/rtc.h>
81#include <machine/stdarg.h>
82#if NFT > 0
83#include <sys/ftape.h>
84#include <i386/isa/ftreg.h>
85#endif
86#ifdef DEVFS
87#include <sys/devfsext.h>
88#endif
89
90
91static int fd_goaway(struct kern_devconf *, int);
92static int fdc_goaway(struct kern_devconf *, int);
93static int fd_externalize(struct kern_devconf *, struct sysctl_req *);
94
95/*
96 * Templates for the kern_devconf structures used when we attach.
97 */
98static struct kern_devconf kdc_fd[NFD] = { {
99	0, 0, 0,		/* filled in by kern_devconf.c */
100	"fd", 0, { MDDT_DISK, 0 },
101	fd_externalize, 0, fd_goaway, DISK_EXTERNALLEN,
102	0,			/* parent */
103	0,			/* parentdata */
104	DC_UNCONFIGURED,	/* state */
105	"floppy disk",
106	DC_CLS_DISK		/* class */
107} };
108
109struct kern_devconf kdc_fdc[NFDC] = { {
110	0, 0, 0,		/* filled in by kern_devconf.c */
111	"fdc", 0, { MDDT_ISA, 0, "bio" },
112	isa_generic_externalize, 0, fdc_goaway, ISA_EXTERNALLEN,
113	0,			/* parent */
114	0,			/* parentdata */
115	DC_UNCONFIGURED,	/* state */
116	"floppy disk/tape controller",
117	DC_CLS_MISC		/* class */
118} };
119
120static inline void
121fd_registerdev(int ctlr, int unit)
122{
123	if(unit != 0)
124		kdc_fd[unit] = kdc_fd[0];
125
126	kdc_fd[unit].kdc_unit = unit;
127	kdc_fd[unit].kdc_parent = &kdc_fdc[ctlr];
128	kdc_fd[unit].kdc_parentdata = 0;
129	dev_attach(&kdc_fd[unit]);
130}
131
132static inline void
133fdc_registerdev(struct isa_device *dvp)
134{
135	int unit = dvp->id_unit;
136
137	if(unit != 0)
138		kdc_fdc[unit] = kdc_fdc[0];
139
140	kdc_fdc[unit].kdc_unit = unit;
141	kdc_fdc[unit].kdc_parent = &kdc_isa0;
142	kdc_fdc[unit].kdc_parentdata = dvp;
143	dev_attach(&kdc_fdc[unit]);
144}
145
146static int
147fdc_goaway(struct kern_devconf *kdc, int force)
148{
149	if(force) {
150		dev_detach(kdc);
151		return 0;
152	} else {
153		return EBUSY;	/* XXX fix */
154	}
155}
156
157static int
158fd_goaway(struct kern_devconf *kdc, int force)
159{
160	dev_detach(kdc);
161	return 0;
162}
163
164#define	b_cylin	b_resid		/* XXX now spelled b_cylinder elsewhere */
165
166/* misuse a flag to identify format operation */
167#define B_FORMAT B_XXX
168
169/*
170 * this biotab field doubles as a field for the physical unit number
171 * on the controller
172 */
173#define id_physid id_scsiid
174
175/* error returns for fd_cmd() */
176#define FD_FAILED -1
177#define FD_NOT_VALID -2
178#define FDC_ERRMAX	100	/* do not log more */
179
180#define NUMTYPES 14
181#define NUMDENS  (NUMTYPES - 6)
182
183/* These defines (-1) must match index for fd_types */
184#define F_TAPE_TYPE	0x020	/* bit for fd_types to indicate tape */
185#define NO_TYPE		0	/* must match NO_TYPE in ft.c */
186#define FD_1720         1
187#define FD_1480         2
188#define FD_1440         3
189#define FD_1200         4
190#define FD_820          5
191#define FD_800          6
192#define FD_720          7
193#define FD_360          8
194
195#define FD_1480in5_25   9
196#define FD_1440in5_25   10
197#define FD_820in5_25    11
198#define FD_800in5_25    12
199#define FD_720in5_25    13
200#define FD_360in5_25    14
201
202
203static struct fd_type fd_types[NUMTYPES] =
204{
205{ 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
206{ 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
207{ 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
208{ 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /*  1.2M in HD 5.25/3.5 */
209{ 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /*  820K in HD 3.5in */
210{ 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /*  800K in HD 3.5in */
211{  9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /*  720K in HD 3.5in */
212{  9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /*  360K in DD 5.25in */
213
214{ 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
215{ 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
216{ 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /*  820K in HD 5.25in */
217{ 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /*  800K in HD 5.25in */
218{  9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /*  720K in HD 5.25in */
219{  9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /*  360K in HD 5.25in */
220};
221
222#define DRVS_PER_CTLR 2		/* 2 floppies */
223
224/***********************************************************************\
225* Per controller structure.						*
226\***********************************************************************/
227struct fdc_data fdc_data[NFDC];
228
229/***********************************************************************\
230* Per drive structure.							*
231* N per controller  (DRVS_PER_CTLR)					*
232\***********************************************************************/
233static struct fd_data {
234	struct	fdc_data *fdc;	/* pointer to controller structure */
235	int	fdsu;		/* this units number on this controller */
236	int	type;		/* Drive type (FD_1440...) */
237	struct	fd_type *ft;	/* pointer to the type descriptor */
238	int	flags;
239#define	FD_OPEN		0x01	/* it's open		*/
240#define	FD_ACTIVE	0x02	/* it's active		*/
241#define	FD_MOTOR	0x04	/* motor should be on	*/
242#define	FD_MOTOR_WAIT	0x08	/* motor coming up	*/
243	int	skip;
244	int	hddrv;
245#define FD_NO_TRACK -2
246	int	track;		/* where we think the head is */
247	int	options;	/* user configurable options, see ioctl_fd.h */
248	int	dkunit;		/* disk stats unit number */
249#ifdef DEVFS
250	void	*bdevs[1 + NUMDENS + MAXPARTITIONS];
251	void	*cdevs[1 + NUMDENS + MAXPARTITIONS];
252#endif
253} fd_data[NFD];
254
255/***********************************************************************\
256* Throughout this file the following conventions will be used:		*
257* fd is a pointer to the fd_data struct for the drive in question	*
258* fdc is a pointer to the fdc_data struct for the controller		*
259* fdu is the floppy drive unit number					*
260* fdcu is the floppy controller unit number				*
261* fdsu is the floppy drive unit number on that controller. (sub-unit)	*
262\***********************************************************************/
263
264#if NFT > 0
265int ftopen(dev_t, int);
266int ftintr(ftu_t ftu);
267int ftclose(dev_t, int);
268void ftstrategy(struct buf *);
269int ftioctl(dev_t, int, caddr_t, int, struct proc *);
270int ftdump(dev_t);
271int ftsize(dev_t);
272int ftattach(struct isa_device *, struct isa_device *, int);
273#endif
274
275/* autoconfig functions */
276static int fdprobe(struct isa_device *);
277static int fdattach(struct isa_device *);
278
279/* needed for ft driver, thus exported */
280int in_fdc(fdcu_t);
281int out_fdc(fdcu_t, int);
282
283/* internal functions */
284static void set_motor(fdcu_t, int, int);
285#  define TURNON 1
286#  define TURNOFF 0
287static timeout_t fd_turnoff;
288static timeout_t fd_motor_on;
289static void fd_turnon(fdu_t);
290static void fdc_reset(fdc_p);
291static int fd_in(fdcu_t, int *);
292static void fdstart(fdcu_t);
293static timeout_t fd_timeout;
294static timeout_t fd_pseudointr;
295static int fdstate(fdcu_t, fdc_p);
296static int retrier(fdcu_t);
297static int fdformat(dev_t, struct fd_formb *, struct proc *);
298
299
300#define DEVIDLE		0
301#define FINDWORK	1
302#define	DOSEEK		2
303#define SEEKCOMPLETE 	3
304#define	IOCOMPLETE	4
305#define RECALCOMPLETE	5
306#define	STARTRECAL	6
307#define	RESETCTLR	7
308#define	SEEKWAIT	8
309#define	RECALWAIT	9
310#define	MOTORWAIT	10
311#define	IOTIMEDOUT	11
312
313#ifdef	DEBUG
314char *fdstates[] =
315{
316"DEVIDLE",
317"FINDWORK",
318"DOSEEK",
319"SEEKCOMPLETE",
320"IOCOMPLETE",
321"RECALCOMPLETE",
322"STARTRECAL",
323"RESETCTLR",
324"SEEKWAIT",
325"RECALWAIT",
326"MOTORWAIT",
327"IOTIMEDOUT"
328};
329
330/* CAUTION: fd_debug causes huge amounts of logging output */
331int	fd_debug = 0;
332#define TRACE0(arg) if(fd_debug) printf(arg)
333#define TRACE1(arg1, arg2) if(fd_debug) printf(arg1, arg2)
334#else /* DEBUG */
335#define TRACE0(arg)
336#define TRACE1(arg1, arg2)
337#endif /* DEBUG */
338
339/* autoconfig structure */
340
341struct	isa_driver fdcdriver = {
342	fdprobe, fdattach, "fdc",
343};
344
345static	d_open_t	Fdopen;	/* NOTE, not fdopen */
346static	d_close_t	fdclose;
347static	d_ioctl_t	fdioctl;
348static	d_strategy_t	fdstrategy;
349
350#define CDEV_MAJOR 9
351#define BDEV_MAJOR 2
352extern	struct cdevsw fd_cdevsw;
353static struct bdevsw fd_bdevsw =
354	{ Fdopen,	fdclose,	fdstrategy,	fdioctl,	/*2*/
355	  nodump,	nopsize,	0,	"fd",	&fd_cdevsw,	-1 };
356
357static struct cdevsw fd_cdevsw =
358	{ Fdopen,	fdclose,	rawread,	rawwrite,	/*9*/
359	  fdioctl,	nostop,		nullreset,	nodevtotty,
360	  seltrue,	nommap,		fdstrategy,	"fd",
361	  &fd_bdevsw,	-1 };
362
363static struct isa_device *fdcdevs[NFDC];
364
365/*
366 * Provide hw.devconf information.
367 */
368static int
369fd_externalize(struct kern_devconf *kdc, struct sysctl_req *req)
370{
371	return disk_externalize(fd_data[kdc->kdc_unit].fdsu, req);
372}
373
374static int
375fdc_err(fdcu_t fdcu, const char *s)
376{
377	fdc_data[fdcu].fdc_errs++;
378	if(s) {
379		if(fdc_data[fdcu].fdc_errs < FDC_ERRMAX)
380			printf("fdc%d: %s", fdcu, s);
381		else if(fdc_data[fdcu].fdc_errs == FDC_ERRMAX)
382			printf("fdc%d: too many errors, not logging any more\n",
383			       fdcu);
384	}
385
386	return FD_FAILED;
387}
388
389/*
390 * fd_cmd: Send a command to the chip.  Takes a varargs with this structure:
391 * Unit number,
392 * # of output bytes, output bytes as ints ...,
393 * # of input bytes, input bytes as ints ...
394 */
395
396static int
397fd_cmd(fdcu_t fdcu, int n_out, ...)
398{
399	u_char cmd;
400	int n_in;
401	int n;
402	va_list ap;
403
404	va_start(ap, n_out);
405	cmd = (u_char)(va_arg(ap, int));
406	va_end(ap);
407	va_start(ap, n_out);
408	for (n = 0; n < n_out; n++)
409	{
410		if (out_fdc(fdcu, va_arg(ap, int)) < 0)
411		{
412			char msg[50];
413			sprintf(msg,
414				"cmd %x failed at out byte %d of %d\n",
415				cmd, n + 1, n_out);
416			return fdc_err(fdcu, msg);
417		}
418	}
419	n_in = va_arg(ap, int);
420	for (n = 0; n < n_in; n++)
421	{
422		int *ptr = va_arg(ap, int *);
423		if (fd_in(fdcu, ptr) < 0)
424		{
425			char msg[50];
426			sprintf(msg,
427				"cmd %02x failed at in byte %d of %d\n",
428				cmd, n + 1, n_in);
429			return fdc_err(fdcu, msg);
430		}
431	}
432
433	return 0;
434}
435
436static int
437fd_sense_drive_status(fdc_p fdc, int *st3p)
438{
439	int st3;
440
441	if (fd_cmd(fdc->fdcu, 2, NE7CMD_SENSED, fdc->fdu, 1, &st3))
442	{
443		return fdc_err(fdc->fdcu, "Sense Drive Status failed\n");
444	}
445	if (st3p)
446		*st3p = st3;
447
448	return 0;
449}
450
451static int
452fd_sense_int(fdc_p fdc, int *st0p, int *cylp)
453{
454	int st0, cyl;
455
456	int ret = fd_cmd(fdc->fdcu, 1, NE7CMD_SENSEI, 1, &st0);
457
458	if (ret)
459	{
460		(void)fdc_err(fdc->fdcu,
461			      "sense intr err reading stat reg 0\n");
462		return ret;
463	}
464
465	if (st0p)
466		*st0p = st0;
467
468	if ((st0 & NE7_ST0_IC) == NE7_ST0_IC_IV)
469	{
470		/*
471		 * There doesn't seem to have been an interrupt.
472		 */
473		return FD_NOT_VALID;
474	}
475
476	if (fd_in(fdc->fdcu, &cyl) < 0)
477	{
478		return fdc_err(fdc->fdcu, "can't get cyl num\n");
479	}
480
481	if (cylp)
482		*cylp = cyl;
483
484	return 0;
485}
486
487
488static int
489fd_read_status(fdc_p fdc, int fdsu)
490{
491	int i, ret;
492
493	for (i = 0; i < 7; i++)
494	{
495		/*
496		 * XXX types are poorly chosen.  Only bytes can by read
497		 * from the hardware, but fdc_status wants u_longs and
498		 * fd_in() gives ints.
499		 */
500		int status;
501
502		ret = fd_in(fdc->fdcu, &status);
503		fdc->status[i] = status;
504		if (ret != 0)
505			break;
506	}
507
508	if (ret == 0)
509		fdc->flags |= FDC_STAT_VALID;
510	else
511		fdc->flags &= ~FDC_STAT_VALID;
512
513	return ret;
514}
515
516/****************************************************************************/
517/*                      autoconfiguration stuff                             */
518/****************************************************************************/
519
520/*
521 * probe for existance of controller
522 */
523static int
524fdprobe(struct isa_device *dev)
525{
526	fdcu_t	fdcu = dev->id_unit;
527	if(fdc_data[fdcu].flags & FDC_ATTACHED)
528	{
529		printf("fdc%d: unit used multiple times\n", fdcu);
530		return 0;
531	}
532
533	fdcdevs[fdcu] = dev;
534	fdc_data[fdcu].baseport = dev->id_iobase;
535
536#ifndef DEV_LKM
537	fdc_registerdev(dev);
538#endif
539
540	/* First - lets reset the floppy controller */
541	outb(dev->id_iobase+FDOUT, 0);
542	DELAY(100);
543	outb(dev->id_iobase+FDOUT, FDO_FRST);
544
545	/* see if it can handle a command */
546	if (fd_cmd(fdcu,
547		   3, NE7CMD_SPECIFY, NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
548		   0))
549	{
550		return(0);
551	}
552	kdc_fdc[fdcu].kdc_state = DC_IDLE;
553	return (IO_FDCSIZE);
554}
555
556/*
557 * wire controller into system, look for floppy units
558 */
559static int
560fdattach(struct isa_device *dev)
561{
562	unsigned fdt;
563	fdu_t	fdu;
564	fdcu_t	fdcu = dev->id_unit;
565	fdc_p	fdc = fdc_data + fdcu;
566	fd_p	fd;
567	int	fdsu, st0, st3, i, unithasfd;
568	struct isa_device *fdup;
569	int ic_type = 0;
570#ifdef DEVFS
571	int	mynor;
572	int	typemynor;
573	int	typesize;
574#endif
575
576	fdc->fdcu = fdcu;
577	fdc->flags |= FDC_ATTACHED;
578	fdc->dmachan = dev->id_drq;
579	isa_dmainit(fdc->dmachan, 128 << 3 /* XXX max secsize */);
580	fdc->state = DEVIDLE;
581	/* reset controller, turn motor off, clear fdout mirror reg */
582	outb(fdc->baseport + FDOUT, ((fdc->fdout = 0)));
583
584	/* check for each floppy drive */
585	for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
586		if (fdup->id_iobase != dev->id_iobase)
587			continue;
588		fdu = fdup->id_unit;
589		fd = &fd_data[fdu];
590		if (fdu >= (NFD+NFT))
591			continue;
592		fdsu = fdup->id_physid;
593		/* look up what bios thinks we have */
594		switch (fdu) {
595			case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
596				break;
597			case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
598				break;
599			default: fdt = RTCFDT_NONE;
600				break;
601		}
602		/* is there a unit? */
603		if ((fdt == RTCFDT_NONE)
604#if NFT > 0
605		    || (fdsu >= DRVS_PER_CTLR)) {
606#else
607		) {
608			fd->type = NO_TYPE;
609#endif
610#if NFT > 0
611			/* If BIOS says no floppy, or > 2nd device */
612			/* Probe for and attach a floppy tape.     */
613			/* Tell FT if there was already a disk     */
614			/* with this unit number found.            */
615
616			unithasfd = 0;
617			if (fdu < NFD && fd->type != NO_TYPE)
618				unithasfd = 1;
619			if (ftattach(dev, fdup, unithasfd))
620				continue;
621			if (fdsu < DRVS_PER_CTLR)
622				fd->type = NO_TYPE;
623#endif
624			continue;
625		}
626
627		/* select it */
628		set_motor(fdcu, fdsu, TURNON);
629		DELAY(1000000);	/* 1 sec */
630
631		if (ic_type == 0 &&
632		    fd_cmd(fdcu, 1, NE7CMD_VERSION, 1, &ic_type) == 0)
633		{
634			printf("fdc%d: ", fdcu);
635			ic_type = (u_char)ic_type;
636			switch( ic_type ) {
637			case 0x80:
638				printf("NEC 765\n");
639				fdc->fdct = FDC_NE765;
640				kdc_fdc[fdcu].kdc_description =
641					"NEC 765 floppy disk/tape controller";
642				break;
643			case 0x81:
644				printf("Intel 82077\n");
645				fdc->fdct = FDC_I82077;
646				kdc_fdc[fdcu].kdc_description =
647					"Intel 82077 floppy disk/tape controller";
648				break;
649			case 0x90:
650				printf("NEC 72065B\n");
651				fdc->fdct = FDC_NE72065;
652				kdc_fdc[fdcu].kdc_description =
653					"NEC 72065B floppy disk/tape controller";
654				break;
655			default:
656				printf("unknown IC type %02x\n", ic_type);
657				fdc->fdct = FDC_UNKNOWN;
658				break;
659			}
660		}
661		if ((fd_cmd(fdcu, 2, NE7CMD_SENSED, fdsu, 1, &st3) == 0) &&
662		    (st3 & NE7_ST3_T0)) {
663			/* if at track 0, first seek inwards */
664			/* seek some steps: */
665			(void)fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0);
666			DELAY(300000); /* ...wait a moment... */
667			(void)fd_sense_int(fdc, 0, 0); /* make ctrlr happy */
668		}
669
670		/* If we're at track 0 first seek inwards. */
671		if ((fd_sense_drive_status(fdc, &st3) == 0) &&
672		    (st3 & NE7_ST3_T0)) {
673			/* Seek some steps... */
674			if (fd_cmd(fdcu, 3, NE7CMD_SEEK, fdsu, 10, 0) == 0) {
675				/* ...wait a moment... */
676				DELAY(300000);
677				/* make ctrlr happy: */
678				(void)fd_sense_int(fdc, 0, 0);
679			}
680		}
681
682		for(i = 0; i < 2; i++) {
683			/*
684			 * we must recalibrate twice, just in case the
685			 * heads have been beyond cylinder 76, since most
686			 * FDCs still barf when attempting to recalibrate
687			 * more than 77 steps
688			 */
689			/* go back to 0: */
690			if (fd_cmd(fdcu, 2, NE7CMD_RECAL, fdsu, 0) == 0) {
691				/* a second being enough for full stroke seek*/
692				DELAY(i == 0? 1000000: 300000);
693
694				/* anything responding? */
695				if (fd_sense_int(fdc, &st0, 0) == 0 &&
696				(st0 & NE7_ST0_EC) == 0)
697					break; /* already probed succesfully */
698			}
699		}
700
701		set_motor(fdcu, fdsu, TURNOFF);
702
703		if (st0 & NE7_ST0_EC) /* no track 0 -> no drive present */
704			continue;
705
706		fd->track = FD_NO_TRACK;
707		fd->fdc = fdc;
708		fd->fdsu = fdsu;
709		fd->options = 0;
710		printf("fd%d: ", fdu);
711
712		fd_registerdev(fdcu, fdu);
713		switch (fdt) {
714		case RTCFDT_12M:
715			printf("1.2MB 5.25in\n");
716			fd->type = FD_1200;
717			kdc_fd[fdu].kdc_description =
718				"1.2MB (1200K) 5.25in floppy disk drive";
719			break;
720		case RTCFDT_144M:
721			printf("1.44MB 3.5in\n");
722			fd->type = FD_1440;
723			kdc_fd[fdu].kdc_description =
724				"1.44MB (1440K) 3.5in floppy disk drive";
725			break;
726		case RTCFDT_288M:
727		case RTCFDT_288M_1:
728			printf("2.88MB 3.5in - 1.44MB mode\n");
729			fd->type = FD_1440;
730			kdc_fd[fdu].kdc_description =
731				"2.88MB (2880K) 3.5in floppy disk drive in 1.44 mode";
732			break;
733		case RTCFDT_360K:
734			printf("360KB 5.25in\n");
735			fd->type = FD_360;
736			kdc_fd[fdu].kdc_description =
737				"360KB 5.25in floppy disk drive";
738			break;
739		case RTCFDT_720K:
740			printf("720KB 3.5in\n");
741			fd->type = FD_720;
742			kdc_fd[fdu].kdc_description =
743				"720KB 3.5in floppy disk drive";
744			break;
745		default:
746			printf("unknown\n");
747			fd->type = NO_TYPE;
748			dev_detach(&kdc_fd[fdu]);
749			continue;
750		}
751		kdc_fd[fdu].kdc_state = DC_IDLE;
752#ifdef DEVFS
753		mynor = fdu << 6;
754		fd->bdevs[0] = devfs_add_devswf(&fd_bdevsw, mynor, DV_BLK,
755						UID_ROOT, GID_OPERATOR, 0640,
756						"fd%d", fdu);
757		fd->cdevs[0] = devfs_add_devswf(&fd_cdevsw, mynor, DV_CHR,
758						UID_ROOT, GID_OPERATOR, 0640,
759						"rfd%d", fdu);
760		for (i = 1; i < 1 + NUMDENS; i++) {
761			/*
762			 * XXX this and the lookup in Fdopen() should be
763			 * data driven.
764			 */
765			switch (fd->type) {
766			case FD_360:
767				if (i != FD_360)
768					continue;
769				break;
770			case FD_720:
771				if (i != FD_720 && i != FD_800 && i != FD_820)
772					continue;
773				break;
774			case FD_1200:
775				if (i != FD_360 && i != FD_720 && i != FD_800
776				    && i != FD_820 && i != FD_1200
777				    && i != FD_1440 && i != FD_1480)
778					continue;
779				break;
780			case FD_1440:
781				if (i != FD_720 && i != FD_800 && i != FD_820
782				    && i != FD_1200 && i != FD_1440
783				    && i != FD_1480 && i != FD_1720)
784					continue;
785				break;
786			}
787			typemynor = mynor | i;
788			typesize = fd_types[i - 1].size / 2;
789			/*
790			 * XXX all these conversions give bloated code and
791			 * confusing names.
792			 */
793			if (typesize == 1476)
794				typesize = 1480;
795			if (typesize == 1722)
796				typesize = 1720;
797			fd->bdevs[i] =
798				devfs_add_devswf(&fd_bdevsw, typemynor, DV_BLK,
799						 UID_ROOT, GID_OPERATOR, 0640,
800						 "fd%d.%d", fdu, typesize);
801			fd->cdevs[i] =
802				devfs_add_devswf(&fd_cdevsw, typemynor, DV_CHR,
803						 UID_ROOT, GID_OPERATOR, 0640,
804						 "rfd%d.%d", fdu, typesize);
805		}
806		for (i = 0; i < MAXPARTITIONS; i++) {
807			fd->bdevs[1 + NUMDENS + i] =
808				devfs_link(fd->bdevs[0],
809					   "fd%d%c", fdu, 'a' + i);
810			fd->cdevs[1 + NUMDENS + i] =
811				devfs_link(fd->cdevs[0],
812					   "rfd%d%c", fdu, 'a' + i);
813		}
814#endif /* DEVFS */
815		if (dk_ndrive < DK_NDRIVE) {
816			sprintf(dk_names[dk_ndrive], "fd%d", fdu);
817			fd->dkunit = dk_ndrive++;
818			/*
819			 * XXX assume rate is FDC_500KBPS.
820			 */
821			dk_wpms[dk_ndrive] = 500000 / 8 / 2;
822		} else {
823			fd->dkunit = -1;
824		}
825	}
826
827	return (1);
828}
829
830/****************************************************************************/
831/*                            motor control stuff                           */
832/*		remember to not deselect the drive we're working on         */
833/****************************************************************************/
834static void
835set_motor(fdcu_t fdcu, int fdsu, int turnon)
836{
837	int fdout = fdc_data[fdcu].fdout;
838	int needspecify = 0;
839
840	if(turnon) {
841		fdout &= ~FDO_FDSEL;
842		fdout |= (FDO_MOEN0 << fdsu) + fdsu;
843	} else
844		fdout &= ~(FDO_MOEN0 << fdsu);
845
846	if(!turnon
847	   && (fdout & (FDO_MOEN0+FDO_MOEN1+FDO_MOEN2+FDO_MOEN3)) == 0)
848		/* gonna turn off the last drive, put FDC to bed */
849		fdout &= ~ (FDO_FRST|FDO_FDMAEN);
850	else {
851		/* make sure controller is selected and specified */
852		if((fdout & (FDO_FRST|FDO_FDMAEN)) == 0)
853			needspecify = 1;
854		fdout |= (FDO_FRST|FDO_FDMAEN);
855	}
856
857	outb(fdc_data[fdcu].baseport+FDOUT, fdout);
858	fdc_data[fdcu].fdout = fdout;
859	kdc_fdc[fdcu].kdc_state = (fdout & FDO_FRST)? DC_BUSY: DC_IDLE;
860	TRACE1("[0x%x->FDOUT]", fdout);
861
862	if(needspecify) {
863		/*
864		 * XXX
865		 * special case: since we have just woken up the FDC
866		 * from its sleep, we silently assume the command will
867		 * be accepted, and do not test for a timeout
868		 */
869		(void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
870			     NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
871			     0);
872	}
873}
874
875static void
876fd_turnoff(void *arg1)
877{
878	fdu_t fdu = (fdu_t)arg1;
879	int	s;
880	fd_p fd = fd_data + fdu;
881
882	TRACE1("[fd%d: turnoff]", fdu);
883
884	/*
885	 * Don't turn off the motor yet if the drive is active.
886	 * XXX shouldn't even schedule turnoff until drive is inactive
887	 * and nothing is queued on it.
888	 */
889	if (fd->fdc->state != DEVIDLE && fd->fdc->fdu == fdu) {
890		timeout(fd_turnoff, arg1, 4 * hz);
891		return;
892	}
893
894	s = splbio();
895	fd->flags &= ~FD_MOTOR;
896	set_motor(fd->fdc->fdcu, fd->fdsu, TURNOFF);
897	splx(s);
898}
899
900static void
901fd_motor_on(void *arg1)
902{
903	fdu_t fdu = (fdu_t)arg1;
904	int	s;
905
906	fd_p fd = fd_data + fdu;
907	s = splbio();
908	fd->flags &= ~FD_MOTOR_WAIT;
909	if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
910	{
911		fdintr(fd->fdc->fdcu);
912	}
913	splx(s);
914}
915
916static void
917fd_turnon(fdu_t fdu)
918{
919	fd_p fd = fd_data + fdu;
920	if(!(fd->flags & FD_MOTOR))
921	{
922		fd->flags |= (FD_MOTOR + FD_MOTOR_WAIT);
923		set_motor(fd->fdc->fdcu, fd->fdsu, TURNON);
924		timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
925	}
926}
927
928static void
929fdc_reset(fdc_p fdc)
930{
931	fdcu_t fdcu = fdc->fdcu;
932
933	/* Try a reset, keep motor on */
934	outb(fdc->baseport + FDOUT, fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
935	TRACE1("[0x%x->FDOUT]", fdc->fdout & ~(FDO_FRST|FDO_FDMAEN));
936	DELAY(100);
937	/* enable FDC, but defer interrupts a moment */
938	outb(fdc->baseport + FDOUT, fdc->fdout & ~FDO_FDMAEN);
939	TRACE1("[0x%x->FDOUT]", fdc->fdout & ~FDO_FDMAEN);
940	DELAY(100);
941	outb(fdc->baseport + FDOUT, fdc->fdout);
942	TRACE1("[0x%x->FDOUT]", fdc->fdout);
943
944	/* XXX after a reset, silently believe the FDC will accept commands */
945	(void)fd_cmd(fdcu, 3, NE7CMD_SPECIFY,
946		     NE7_SPEC_1(3, 240), NE7_SPEC_2(2, 0),
947		     0);
948}
949
950/****************************************************************************/
951/*                             fdc in/out                                   */
952/****************************************************************************/
953int
954in_fdc(fdcu_t fdcu)
955{
956	int baseport = fdc_data[fdcu].baseport;
957	int i, j = 100000;
958	while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
959		!= (NE7_DIO|NE7_RQM) && j-- > 0)
960		if (i == NE7_RQM)
961			return fdc_err(fdcu, "ready for output in input\n");
962	if (j <= 0)
963		return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0);
964#ifdef	DEBUG
965	i = inb(baseport+FDDATA);
966	TRACE1("[FDDATA->0x%x]", (unsigned char)i);
967	return(i);
968#else
969	return inb(baseport+FDDATA);
970#endif
971}
972
973/*
974 * fd_in: Like in_fdc, but allows you to see if it worked.
975 */
976static int
977fd_in(fdcu_t fdcu, int *ptr)
978{
979	int baseport = fdc_data[fdcu].baseport;
980	int i, j = 100000;
981	while ((i = inb(baseport+FDSTS) & (NE7_DIO|NE7_RQM))
982		!= (NE7_DIO|NE7_RQM) && j-- > 0)
983		if (i == NE7_RQM)
984			return fdc_err(fdcu, "ready for output in input\n");
985	if (j <= 0)
986		return fdc_err(fdcu, bootverbose? "input ready timeout\n": 0);
987#ifdef	DEBUG
988	i = inb(baseport+FDDATA);
989	TRACE1("[FDDATA->0x%x]", (unsigned char)i);
990	*ptr = i;
991	return 0;
992#else
993	i = inb(baseport+FDDATA);
994	if (ptr)
995		*ptr = i;
996	return 0;
997#endif
998}
999
1000int
1001out_fdc(fdcu_t fdcu, int x)
1002{
1003	int baseport = fdc_data[fdcu].baseport;
1004	int i;
1005
1006	/* Check that the direction bit is set */
1007	i = 100000;
1008	while ((inb(baseport+FDSTS) & NE7_DIO) && i-- > 0);
1009	if (i <= 0) return fdc_err(fdcu, "direction bit not set\n");
1010
1011	/* Check that the floppy controller is ready for a command */
1012	i = 100000;
1013	while ((inb(baseport+FDSTS) & NE7_RQM) == 0 && i-- > 0);
1014	if (i <= 0)
1015		return fdc_err(fdcu, bootverbose? "output ready timeout\n": 0);
1016
1017	/* Send the command and return */
1018	outb(baseport+FDDATA, x);
1019	TRACE1("[0x%x->FDDATA]", x);
1020	return (0);
1021}
1022
1023/****************************************************************************/
1024/*                           fdopen/fdclose                                 */
1025/****************************************************************************/
1026int
1027Fdopen(dev_t dev, int flags, int mode, struct proc *p)
1028{
1029 	fdu_t fdu = FDUNIT(minor(dev));
1030	int type = FDTYPE(minor(dev));
1031	fdc_p	fdc;
1032
1033#if NFT > 0
1034	/* check for a tape open */
1035	if (type & F_TAPE_TYPE)
1036		return(ftopen(dev, flags));
1037#endif
1038	/* check bounds */
1039	if (fdu >= NFD)
1040		return(ENXIO);
1041	fdc = fd_data[fdu].fdc;
1042	if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
1043		return(ENXIO);
1044	if (type > NUMDENS)
1045		return(ENXIO);
1046	if (type == 0)
1047		type = fd_data[fdu].type;
1048	else {
1049		if (type != fd_data[fdu].type) {
1050			switch (fd_data[fdu].type) {
1051			case FD_360:
1052				return(ENXIO);
1053			case FD_720:
1054				if (   type != FD_820
1055				    && type != FD_800
1056				   )
1057					return(ENXIO);
1058				break;
1059			case FD_1200:
1060				switch (type) {
1061				case FD_1480:
1062					type = FD_1480in5_25;
1063					break;
1064				case FD_1440:
1065					type = FD_1440in5_25;
1066					break;
1067				case FD_820:
1068					type = FD_820in5_25;
1069					break;
1070				case FD_800:
1071					type = FD_800in5_25;
1072					break;
1073				case FD_720:
1074					type = FD_720in5_25;
1075					break;
1076				case FD_360:
1077					type = FD_360in5_25;
1078					break;
1079				default:
1080					return(ENXIO);
1081				}
1082				break;
1083			case FD_1440:
1084				if (   type != FD_1720
1085				    && type != FD_1480
1086				    && type != FD_1200
1087				    && type != FD_820
1088				    && type != FD_800
1089				    && type != FD_720
1090				    )
1091					return(ENXIO);
1092				break;
1093			}
1094		}
1095	}
1096	fd_data[fdu].ft = fd_types + type - 1;
1097	fd_data[fdu].flags |= FD_OPEN;
1098	kdc_fd[fdu].kdc_state = DC_BUSY;
1099
1100	return 0;
1101}
1102
1103int
1104fdclose(dev_t dev, int flags, int mode, struct proc *p)
1105{
1106 	fdu_t fdu = FDUNIT(minor(dev));
1107
1108#if NFT > 0
1109	int type = FDTYPE(minor(dev));
1110
1111	if (type & F_TAPE_TYPE)
1112		return ftclose(dev, flags);
1113#endif
1114	fd_data[fdu].flags &= ~FD_OPEN;
1115	fd_data[fdu].options &= ~FDOPT_NORETRY;
1116	kdc_fd[fdu].kdc_state = DC_IDLE;
1117
1118	return(0);
1119}
1120
1121
1122/****************************************************************************/
1123/*                               fdstrategy                                 */
1124/****************************************************************************/
1125void
1126fdstrategy(struct buf *bp)
1127{
1128	register struct buf *dp;
1129	long nblocks, blknum;
1130 	int	s;
1131 	fdcu_t	fdcu;
1132 	fdu_t	fdu;
1133 	fdc_p	fdc;
1134 	fd_p	fd;
1135	size_t	fdblk;
1136
1137 	fdu = FDUNIT(minor(bp->b_dev));
1138	fd = &fd_data[fdu];
1139	fdc = fd->fdc;
1140	fdcu = fdc->fdcu;
1141
1142#if NFT > 0
1143	if (FDTYPE(minor(bp->b_dev)) & F_TAPE_TYPE) {
1144		/* ft tapes do not (yet) support strategy i/o */
1145		bp->b_error = ENODEV;
1146		bp->b_flags |= B_ERROR;
1147		goto bad;
1148	}
1149	/* check for controller already busy with tape */
1150	if (fdc->flags & FDC_TAPE_BUSY) {
1151		bp->b_error = EBUSY;
1152		bp->b_flags |= B_ERROR;
1153		goto bad;
1154	}
1155#endif
1156	fdblk = 128 << (fd->ft->secsize);
1157	if (!(bp->b_flags & B_FORMAT)) {
1158		if ((fdu >= NFD) || (bp->b_blkno < 0)) {
1159			printf(
1160		"fd%d: fdstrat: bad request blkno = %lu, bcount = %ld\n",
1161			       fdu, (u_long)bp->b_blkno, bp->b_bcount);
1162			bp->b_error = EINVAL;
1163			bp->b_flags |= B_ERROR;
1164			goto bad;
1165		}
1166		if ((bp->b_bcount % fdblk) != 0) {
1167			bp->b_error = EINVAL;
1168			bp->b_flags |= B_ERROR;
1169			goto bad;
1170		}
1171	}
1172
1173	/*
1174	 * Set up block calculations.
1175	 */
1176	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/fdblk;
1177 	nblocks = fd->ft->size;
1178	if (blknum + (bp->b_bcount / fdblk) > nblocks) {
1179		if (blknum == nblocks) {
1180			bp->b_resid = bp->b_bcount;
1181		} else {
1182			bp->b_error = ENOSPC;
1183			bp->b_flags |= B_ERROR;
1184		}
1185		goto bad;
1186	}
1187 	bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
1188 	bp->b_pblkno = bp->b_blkno;
1189	dp = &(fdc->head);
1190	s = splbio();
1191	disksort(dp, bp);
1192	untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
1193	fdstart(fdcu);
1194	splx(s);
1195	return;
1196
1197bad:
1198	biodone(bp);
1199}
1200
1201/***************************************************************\
1202*				fdstart				*
1203* We have just queued something.. if the controller is not busy	*
1204* then simulate the case where it has just finished a command	*
1205* So that it (the interrupt routine) looks on the queue for more*
1206* work to do and picks up what we just added.			*
1207* If the controller is already busy, we need do nothing, as it	*
1208* will pick up our work when the present work completes		*
1209\***************************************************************/
1210static void
1211fdstart(fdcu_t fdcu)
1212{
1213	int s;
1214
1215	s = splbio();
1216	if(fdc_data[fdcu].state == DEVIDLE)
1217	{
1218		fdintr(fdcu);
1219	}
1220	splx(s);
1221}
1222
1223static void
1224fd_timeout(void *arg1)
1225{
1226	fdcu_t fdcu = (fdcu_t)arg1;
1227	fdu_t fdu = fdc_data[fdcu].fdu;
1228	int baseport = fdc_data[fdcu].baseport;
1229	struct buf *dp, *bp;
1230	int s;
1231
1232	dp = &fdc_data[fdcu].head;
1233	bp = dp->b_actf;
1234
1235	/*
1236	 * Due to IBM's brain-dead design, the FDC has a faked ready
1237	 * signal, hardwired to ready == true. Thus, any command
1238	 * issued if there's no diskette in the drive will _never_
1239	 * complete, and must be aborted by resetting the FDC.
1240	 * Many thanks, Big Blue!
1241	 */
1242
1243	s = splbio();
1244
1245	TRACE1("fd%d[fd_timeout()]", fdu);
1246	/* See if the controller is still busy (patiently awaiting data) */
1247	if(((inb(baseport + FDSTS)) & (NE7_CB|NE7_RQM)) == NE7_CB)
1248	{
1249		TRACE1("[FDSTS->0x%x]", inb(baseport + FDSTS));
1250		/* yup, it is; kill it now */
1251		fdc_reset(&fdc_data[fdcu]);
1252		printf("fd%d: Operation timeout\n", fdu);
1253	}
1254
1255	if (bp)
1256	{
1257		retrier(fdcu);
1258		fdc_data[fdcu].status[0] = NE7_ST0_IC_RC;
1259		fdc_data[fdcu].state = IOTIMEDOUT;
1260		if( fdc_data[fdcu].retry < 6)
1261			fdc_data[fdcu].retry = 6;
1262	}
1263	else
1264	{
1265		fdc_data[fdcu].fd = (fd_p) 0;
1266		fdc_data[fdcu].fdu = -1;
1267		fdc_data[fdcu].state = DEVIDLE;
1268	}
1269	fdintr(fdcu);
1270	splx(s);
1271}
1272
1273/* just ensure it has the right spl */
1274static void
1275fd_pseudointr(void *arg1)
1276{
1277	fdcu_t fdcu = (fdcu_t)arg1;
1278	int	s;
1279
1280	s = splbio();
1281	fdintr(fdcu);
1282	splx(s);
1283}
1284
1285/***********************************************************************\
1286*                                 fdintr				*
1287* keep calling the state machine until it returns a 0			*
1288* ALWAYS called at SPLBIO 						*
1289\***********************************************************************/
1290void
1291fdintr(fdcu_t fdcu)
1292{
1293	fdc_p fdc = fdc_data + fdcu;
1294#if NFT > 0
1295	fdu_t fdu = fdc->fdu;
1296
1297	if (fdc->flags & FDC_TAPE_BUSY)
1298		(ftintr(fdu));
1299	else
1300#endif
1301		while(fdstate(fdcu, fdc))
1302			;
1303}
1304
1305/***********************************************************************\
1306* The controller state machine.						*
1307* if it returns a non zero value, it should be called again immediatly	*
1308\***********************************************************************/
1309static int
1310fdstate(fdcu_t fdcu, fdc_p fdc)
1311{
1312	int read, format, head, sec = 0, sectrac, st0, cyl, st3;
1313	unsigned long blknum;
1314	fdu_t fdu = fdc->fdu;
1315	fd_p fd;
1316	register struct buf *dp, *bp;
1317	struct fd_formb *finfo = NULL;
1318	size_t fdblk;
1319
1320	dp = &(fdc->head);
1321	bp = dp->b_actf;
1322	if(!bp)
1323	{
1324		/***********************************************\
1325		* nothing left for this controller to do	*
1326		* Force into the IDLE state,			*
1327		\***********************************************/
1328		fdc->state = DEVIDLE;
1329		if(fdc->fd)
1330		{
1331			printf("fd%d: unexpected valid fd pointer\n",
1332			       fdc->fdu);
1333			fdc->fd = (fd_p) 0;
1334			fdc->fdu = -1;
1335		}
1336		TRACE1("[fdc%d IDLE]", fdcu);
1337 		return(0);
1338	}
1339	fdu = FDUNIT(minor(bp->b_dev));
1340	fd = fd_data + fdu;
1341	fdblk = 128 << fd->ft->secsize;
1342	if (fdc->fd && (fd != fdc->fd))
1343	{
1344		printf("fd%d: confused fd pointers\n", fdu);
1345	}
1346	read = bp->b_flags & B_READ;
1347	format = bp->b_flags & B_FORMAT;
1348	if(format)
1349		finfo = (struct fd_formb *)bp->b_un.b_addr;
1350	TRACE1("fd%d", fdu);
1351	TRACE1("[%s]", fdstates[fdc->state]);
1352	TRACE1("(0x%x)", fd->flags);
1353	untimeout(fd_turnoff, (caddr_t)fdu);
1354	timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
1355	switch (fdc->state)
1356	{
1357	case DEVIDLE:
1358	case FINDWORK:	/* we have found new work */
1359		fdc->retry = 0;
1360		fd->skip = 0;
1361		fdc->fd = fd;
1362		fdc->fdu = fdu;
1363		outb(fdc->baseport+FDCTL, fd->ft->trans);
1364		TRACE1("[0x%x->FDCTL]", fd->ft->trans);
1365		/*******************************************************\
1366		* If the next drive has a motor startup pending, then	*
1367		* it will start up in it's own good time		*
1368		\*******************************************************/
1369		if(fd->flags & FD_MOTOR_WAIT)
1370		{
1371			fdc->state = MOTORWAIT;
1372			return(0); /* come back later */
1373		}
1374		/*******************************************************\
1375		* Maybe if it's not starting, it SHOULD be starting	*
1376		\*******************************************************/
1377		if (!(fd->flags & FD_MOTOR))
1378		{
1379			fdc->state = MOTORWAIT;
1380			fd_turnon(fdu);
1381			return(0);
1382		}
1383		else	/* at least make sure we are selected */
1384		{
1385			set_motor(fdcu, fd->fdsu, TURNON);
1386		}
1387		fdc->state = DOSEEK;
1388		break;
1389	case DOSEEK:
1390		if (bp->b_cylin == fd->track)
1391		{
1392			fdc->state = SEEKCOMPLETE;
1393			break;
1394		}
1395		if (fd_cmd(fdcu, 3, NE7CMD_SEEK,
1396			   fd->fdsu, bp->b_cylin * fd->ft->steptrac,
1397			   0))
1398		{
1399			/*
1400			 * seek command not accepted, looks like
1401			 * the FDC went off to the Saints...
1402			 */
1403			fdc->retry = 6;	/* try a reset */
1404			return(retrier(fdcu));
1405		}
1406		fd->track = FD_NO_TRACK;
1407		fdc->state = SEEKWAIT;
1408		return(0);	/* will return later */
1409	case SEEKWAIT:
1410		/* allow heads to settle */
1411		timeout(fd_pseudointr, (caddr_t)fdcu, hz / 16);
1412		fdc->state = SEEKCOMPLETE;
1413		return(0);	/* will return later */
1414	case SEEKCOMPLETE : /* SEEK DONE, START DMA */
1415		/* Make sure seek really happened*/
1416		if(fd->track == FD_NO_TRACK)
1417		{
1418			int descyl = bp->b_cylin * fd->ft->steptrac;
1419			do {
1420				/*
1421				 * This might be a "ready changed" interrupt,
1422				 * which cannot really happen since the
1423				 * RDY pin is hardwired to + 5 volts.  This
1424				 * generally indicates a "bouncing" intr
1425				 * line, so do one of the following:
1426				 *
1427				 * When running on an enhanced FDC that is
1428				 * known to not go stuck after responding
1429				 * with INVALID, fetch all interrupt states
1430				 * until seeing either an INVALID or a
1431				 * real interrupt condition.
1432				 *
1433				 * When running on a dumb old NE765, give
1434				 * up immediately.  The controller will
1435				 * provide up to four dummy RC interrupt
1436				 * conditions right after reset (for the
1437				 * corresponding four drives), so this is
1438				 * our only chance to get notice that it
1439				 * was not the FDC that caused the interrupt.
1440				 */
1441				if (fd_sense_int(fdc, &st0, &cyl)
1442				    == FD_NOT_VALID)
1443					return 0;
1444				if(fdc->fdct == FDC_NE765
1445				   && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
1446					return 0; /* hope for a real intr */
1447			} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
1448
1449			if (0 == descyl)
1450			{
1451				int failed = 0;
1452				/*
1453				 * seek to cyl 0 requested; make sure we are
1454				 * really there
1455				 */
1456				if (fd_sense_drive_status(fdc, &st3))
1457					failed = 1;
1458				if ((st3 & NE7_ST3_T0) == 0) {
1459					printf(
1460		"fd%d: Seek to cyl 0, but not really there (ST3 = %b)\n",
1461					       fdu, st3, NE7_ST3BITS);
1462					failed = 1;
1463				}
1464
1465				if (failed)
1466				{
1467					if(fdc->retry < 3)
1468						fdc->retry = 3;
1469					return(retrier(fdcu));
1470				}
1471			}
1472
1473			if (cyl != descyl)
1474			{
1475				printf(
1476		"fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
1477				       fdu, descyl, cyl, st0);
1478				return(retrier(fdcu));
1479			}
1480		}
1481
1482		fd->track = bp->b_cylin;
1483		if(format)
1484			fd->skip = (char *)&(finfo->fd_formb_cylno(0))
1485				- (char *)finfo;
1486		isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
1487			format ? bp->b_bcount : fdblk, fdc->dmachan);
1488		blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk
1489			+ fd->skip/fdblk;
1490		sectrac = fd->ft->sectrac;
1491		sec = blknum %  (sectrac * fd->ft->heads);
1492		head = sec / sectrac;
1493		sec = sec % sectrac + 1;
1494		fd->hddrv = ((head&1)<<2)+fdu;
1495
1496		if(format || !read)
1497		{
1498			/* make sure the drive is writable */
1499			if(fd_sense_drive_status(fdc, &st3) != 0)
1500			{
1501				/* stuck controller? */
1502				fdc->retry = 6;	/* reset the beast */
1503				return(retrier(fdcu));
1504			}
1505			if(st3 & NE7_ST3_WP)
1506			{
1507				/*
1508				 * XXX YES! this is ugly.
1509				 * in order to force the current operation
1510				 * to fail, we will have to fake an FDC
1511				 * error - all error handling is done
1512				 * by the retrier()
1513				 */
1514				fdc->status[0] = NE7_ST0_IC_AT;
1515				fdc->status[1] = NE7_ST1_NW;
1516				fdc->status[2] = 0;
1517				fdc->status[3] = fd->track;
1518				fdc->status[4] = head;
1519				fdc->status[5] = sec;
1520				fdc->retry = 8;	/* break out immediately */
1521				fdc->state = IOTIMEDOUT; /* not really... */
1522				return (1);
1523			}
1524		}
1525
1526		if(format)
1527		{
1528			/* formatting */
1529			if(fd_cmd(fdcu, 6,
1530				  NE7CMD_FORMAT,
1531				  head << 2 | fdu,
1532				  finfo->fd_formb_secshift,
1533				  finfo->fd_formb_nsecs,
1534				  finfo->fd_formb_gaplen,
1535				  finfo->fd_formb_fillbyte,
1536				  0))
1537			{
1538				/* controller fell over */
1539				fdc->retry = 6;
1540				return(retrier(fdcu));
1541			}
1542		}
1543		else
1544		{
1545			if (fd_cmd(fdcu, 9,
1546				   (read ? NE7CMD_READ : NE7CMD_WRITE),
1547				   head << 2 | fdu,  /* head & unit */
1548				   fd->track,        /* track */
1549				   head,
1550				   sec,              /* sector + 1 */
1551				   fd->ft->secsize,  /* sector size */
1552				   sectrac,          /* sectors/track */
1553				   fd->ft->gap,      /* gap size */
1554				   fd->ft->datalen,  /* data length */
1555				   0))
1556			{
1557				/* the beast is sleeping again */
1558				fdc->retry = 6;
1559				return(retrier(fdcu));
1560			}
1561		}
1562		fdc->state = IOCOMPLETE;
1563		timeout(fd_timeout, (caddr_t)fdcu, hz);
1564		return(0);	/* will return later */
1565	case IOCOMPLETE: /* IO DONE, post-analyze */
1566		untimeout(fd_timeout, (caddr_t)fdcu);
1567
1568		if (fd_read_status(fdc, fd->fdsu))
1569		{
1570			if (fdc->retry < 6)
1571				fdc->retry = 6;	/* force a reset */
1572			return retrier(fdcu);
1573  		}
1574
1575		fdc->state = IOTIMEDOUT;
1576
1577		/* FALLTHROUGH */
1578
1579	case IOTIMEDOUT:
1580		isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
1581			    format ? bp->b_bcount : fdblk, fdc->dmachan);
1582		if (fdc->status[0] & NE7_ST0_IC)
1583		{
1584                        if ((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
1585			    && fdc->status[1] & NE7_ST1_OR) {
1586                                /*
1587				 * DMA overrun. Someone hogged the bus
1588				 * and didn't release it in time for the
1589				 * next FDC transfer.
1590				 * Just restart it, don't increment retry
1591				 * count. (vak)
1592                                 */
1593                                fdc->state = SEEKCOMPLETE;
1594                                return (1);
1595                        }
1596			else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_IV
1597				&& fdc->retry < 6)
1598				fdc->retry = 6;	/* force a reset */
1599			else if((fdc->status[0] & NE7_ST0_IC) == NE7_ST0_IC_AT
1600				&& fdc->status[2] & NE7_ST2_WC
1601				&& fdc->retry < 3)
1602				fdc->retry = 3;	/* force recalibrate */
1603			return(retrier(fdcu));
1604		}
1605		/* All OK */
1606		fd->skip += fdblk;
1607		if (!format && fd->skip < bp->b_bcount)
1608		{
1609			/* set up next transfer */
1610			blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/fdblk
1611				+ fd->skip/fdblk;
1612			bp->b_cylin =
1613				(blknum / (fd->ft->sectrac * fd->ft->heads));
1614			fdc->state = DOSEEK;
1615		}
1616		else
1617		{
1618			/* ALL DONE */
1619			fd->skip = 0;
1620			bp->b_resid = 0;
1621			dp->b_actf = bp->b_actf;
1622			biodone(bp);
1623			fdc->fd = (fd_p) 0;
1624			fdc->fdu = -1;
1625			fdc->state = FINDWORK;
1626		}
1627		return(1);
1628	case RESETCTLR:
1629		fdc_reset(fdc);
1630		fdc->retry++;
1631		fdc->state = STARTRECAL;
1632		break;
1633	case STARTRECAL:
1634		/* XXX clear the fdc results from the last reset, if any. */
1635		{
1636			int i;
1637			for (i = 0; i < 4; i++)
1638				(void)fd_sense_int(fdc, &st0, &cyl);
1639		}
1640
1641		if(fd_cmd(fdcu,
1642			  2, NE7CMD_RECAL, fdu,
1643			  0)) /* Recalibrate Function */
1644		{
1645			/* arrgl */
1646			fdc->retry = 6;
1647			return(retrier(fdcu));
1648		}
1649		fdc->state = RECALWAIT;
1650		return(0);	/* will return later */
1651	case RECALWAIT:
1652		/* allow heads to settle */
1653		timeout(fd_pseudointr, (caddr_t)fdcu, hz / 8);
1654		fdc->state = RECALCOMPLETE;
1655		return(0);	/* will return later */
1656	case RECALCOMPLETE:
1657		do {
1658			/*
1659			 * See SEEKCOMPLETE for a comment on this:
1660			 */
1661			if (fd_sense_int(fdc, &st0, &cyl) == FD_NOT_VALID)
1662				return 0;
1663			if(fdc->fdct == FDC_NE765
1664			   && (st0 & NE7_ST0_IC) == NE7_ST0_IC_RC)
1665				return 0; /* hope for a real intr */
1666		} while ((st0 & NE7_ST0_IC) == NE7_ST0_IC_RC);
1667		if ((st0 & NE7_ST0_IC) != NE7_ST0_IC_NT || cyl != 0)
1668		{
1669			if(fdc->retry > 3)
1670				/*
1671				 * a recalibrate from beyond cylinder 77
1672				 * will "fail" due to the FDC limitations;
1673				 * since people used to complain much about
1674				 * the failure message, try not logging
1675				 * this one if it seems to be the first
1676				 * time in a line
1677				 */
1678				printf("fd%d: recal failed ST0 %b cyl %d\n",
1679				       fdu, st0, NE7_ST0BITS, cyl);
1680			if(fdc->retry < 3) fdc->retry = 3;
1681			return(retrier(fdcu));
1682		}
1683		fd->track = 0;
1684		/* Seek (probably) necessary */
1685		fdc->state = DOSEEK;
1686		return(1);	/* will return immediatly */
1687	case MOTORWAIT:
1688		if(fd->flags & FD_MOTOR_WAIT)
1689		{
1690			return(0); /* time's not up yet */
1691		}
1692		/*
1693		 * since the controller was off, it has lost its
1694		 * idea about the current track it were; thus,
1695		 * recalibrate the bastard
1696		 */
1697		fdc->state = STARTRECAL;
1698		return(1);	/* will return immediatly */
1699	default:
1700		printf("fdc%d: Unexpected FD int->", fdcu);
1701		if (fd_read_status(fdc, fd->fdsu) == 0)
1702			printf("FDC status :%lx %lx %lx %lx %lx %lx %lx   ",
1703			       fdc->status[0],
1704			       fdc->status[1],
1705			       fdc->status[2],
1706			       fdc->status[3],
1707			       fdc->status[4],
1708			       fdc->status[5],
1709			       fdc->status[6] );
1710		else
1711			printf("No status available   ");
1712		if (fd_sense_int(fdc, &st0, &cyl) != 0)
1713		{
1714			printf("[controller is dead now]\n");
1715			return(0);
1716		}
1717		printf("ST0 = %x, PCN = %x\n", st0, cyl);
1718		return(0);
1719	}
1720	/*XXX confusing: some branches return immediately, others end up here*/
1721	return(1); /* Come back immediatly to new state */
1722}
1723
1724static int
1725retrier(fdcu)
1726	fdcu_t fdcu;
1727{
1728	fdc_p fdc = fdc_data + fdcu;
1729	register struct buf *dp, *bp;
1730
1731	dp = &(fdc->head);
1732	bp = dp->b_actf;
1733
1734	if(fd_data[FDUNIT(minor(bp->b_dev))].options & FDOPT_NORETRY)
1735		goto fail;
1736	switch(fdc->retry)
1737	{
1738	case 0: case 1: case 2:
1739		fdc->state = SEEKCOMPLETE;
1740		break;
1741	case 3: case 4: case 5:
1742		fdc->state = STARTRECAL;
1743		break;
1744	case 6:
1745		fdc->state = RESETCTLR;
1746		break;
1747	case 7:
1748		break;
1749	default:
1750	fail:
1751		{
1752			dev_t sav_b_dev = bp->b_dev;
1753			/* Trick diskerr */
1754			bp->b_dev = makedev(major(bp->b_dev),
1755					    (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
1756			diskerr(bp, "fd", "hard error", LOG_PRINTF,
1757				fdc->fd->skip / DEV_BSIZE,
1758				(struct disklabel *)NULL);
1759			bp->b_dev = sav_b_dev;
1760			if (fdc->flags & FDC_STAT_VALID)
1761			{
1762				printf(
1763			" (ST0 %b ST1 %b ST2 %b cyl %ld hd %ld sec %ld)\n",
1764				       fdc->status[0], NE7_ST0BITS,
1765				       fdc->status[1], NE7_ST1BITS,
1766				       fdc->status[2], NE7_ST2BITS,
1767				       fdc->status[3], fdc->status[4],
1768				       fdc->status[5]);
1769			}
1770			else
1771				printf(" (No status)\n");
1772		}
1773		bp->b_flags |= B_ERROR;
1774		bp->b_error = EIO;
1775		bp->b_resid = bp->b_bcount - fdc->fd->skip;
1776		dp->b_actf = bp->b_actf;
1777		fdc->fd->skip = 0;
1778		biodone(bp);
1779		fdc->state = FINDWORK;
1780		fdc->fd = (fd_p) 0;
1781		fdc->fdu = -1;
1782		/* XXX abort current command, if any.  */
1783		return(1);
1784	}
1785	fdc->retry++;
1786	return(1);
1787}
1788
1789static int
1790fdformat(dev, finfo, p)
1791	dev_t dev;
1792	struct fd_formb *finfo;
1793	struct proc *p;
1794{
1795 	fdu_t	fdu;
1796 	fd_p	fd;
1797
1798	struct buf *bp;
1799	int rv = 0, s;
1800	size_t fdblk;
1801
1802 	fdu = FDUNIT(minor(dev));
1803	fd = &fd_data[fdu];
1804	fdblk = 128 << fd->ft->secsize;
1805
1806	/* set up a buffer header for fdstrategy() */
1807	bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1808	if(bp == 0)
1809		return ENOBUFS;
1810	/*
1811	 * keep the process from being swapped
1812	 */
1813	p->p_flag |= P_PHYSIO;
1814	bzero((void *)bp, sizeof(struct buf));
1815	bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1816	bp->b_proc = p;
1817	bp->b_dev = dev;
1818
1819	/*
1820	 * calculate a fake blkno, so fdstrategy() would initiate a
1821	 * seek to the requested cylinder
1822	 */
1823	bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
1824		+ finfo->head * fd->ft->sectrac) * fdblk / DEV_BSIZE;
1825
1826	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1827	bp->b_un.b_addr = (caddr_t)finfo;
1828
1829	/* now do the format */
1830	fdstrategy(bp);
1831
1832	/* ...and wait for it to complete */
1833	s = splbio();
1834	while(!(bp->b_flags & B_DONE))
1835	{
1836		rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1837		if(rv == EWOULDBLOCK)
1838			break;
1839	}
1840	splx(s);
1841
1842	if(rv == EWOULDBLOCK) {
1843		/* timed out */
1844		rv = EIO;
1845		biodone(bp);
1846	}
1847	if(bp->b_flags & B_ERROR)
1848		rv = bp->b_error;
1849	/*
1850	 * allow the process to be swapped
1851	 */
1852	p->p_flag &= ~P_PHYSIO;
1853	free(bp, M_TEMP);
1854	return rv;
1855}
1856
1857/*
1858 * TODO: don't allocate buffer on stack.
1859 */
1860
1861int
1862fdioctl(dev, cmd, addr, flag, p)
1863	dev_t dev;
1864	int cmd;
1865	caddr_t addr;
1866	int flag;
1867	struct proc *p;
1868{
1869 	fdu_t	fdu = FDUNIT(minor(dev));
1870 	fd_p	fd = &fd_data[fdu];
1871	size_t fdblk;
1872
1873	struct fd_type *fdt;
1874	struct disklabel *dl;
1875	char buffer[DEV_BSIZE];
1876	int error = 0;
1877
1878#if NFT > 0
1879	int type = FDTYPE(minor(dev));
1880
1881	/* check for a tape ioctl */
1882	if (type & F_TAPE_TYPE)
1883		return ftioctl(dev, cmd, addr, flag, p);
1884#endif
1885
1886	fdblk = 128 << fd->ft->secsize;
1887
1888	switch (cmd)
1889	{
1890	case DIOCGDINFO:
1891		bzero(buffer, sizeof (buffer));
1892		dl = (struct disklabel *)buffer;
1893		dl->d_secsize = fdblk;
1894		fdt = fd_data[FDUNIT(minor(dev))].ft;
1895		dl->d_secpercyl = fdt->size / fdt->tracks;
1896		dl->d_type = DTYPE_FLOPPY;
1897
1898		if (readdisklabel(dkmodpart(dev, RAW_PART), fdstrategy, dl)
1899		    == NULL)
1900			error = 0;
1901		else
1902			error = EINVAL;
1903
1904		*(struct disklabel *)addr = *dl;
1905		break;
1906
1907	case DIOCSDINFO:
1908		if ((flag & FWRITE) == 0)
1909			error = EBADF;
1910		break;
1911
1912	case DIOCWLABEL:
1913		if ((flag & FWRITE) == 0)
1914			error = EBADF;
1915		break;
1916
1917	case DIOCWDINFO:
1918		if ((flag & FWRITE) == 0)
1919		{
1920			error = EBADF;
1921			break;
1922		}
1923
1924		dl = (struct disklabel *)addr;
1925
1926		if ((error = setdisklabel((struct disklabel *)buffer, dl,
1927					  (u_long)0)) != 0)
1928			break;
1929
1930		error = writedisklabel(dev, fdstrategy,
1931				       (struct disklabel *)buffer);
1932		break;
1933
1934	case FD_FORM:
1935		if((flag & FWRITE) == 0)
1936			error = EBADF;	/* must be opened for writing */
1937		else if(((struct fd_formb *)addr)->format_version !=
1938			FD_FORMAT_VERSION)
1939			error = EINVAL;	/* wrong version of formatting prog */
1940		else
1941			error = fdformat(dev, (struct fd_formb *)addr, p);
1942		break;
1943
1944	case FD_GTYPE:                  /* get drive type */
1945		*(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
1946		break;
1947
1948	case FD_STYPE:                  /* set drive type */
1949		/* this is considered harmful; only allow for superuser */
1950		if(suser(p->p_ucred, &p->p_acflag) != 0)
1951			return EPERM;
1952		*fd_data[FDUNIT(minor(dev))].ft = *(struct fd_type *)addr;
1953		break;
1954
1955	case FD_GOPTS:			/* get drive options */
1956		*(int *)addr = fd_data[FDUNIT(minor(dev))].options;
1957		break;
1958
1959	case FD_SOPTS:			/* set drive options */
1960		fd_data[FDUNIT(minor(dev))].options = *(int *)addr;
1961		break;
1962
1963	default:
1964		error = ENOTTY;
1965		break;
1966	}
1967	return (error);
1968}
1969
1970
1971static fd_devsw_installed = 0;
1972
1973static void 	fd_drvinit(void *notused )
1974{
1975	dev_t dev;
1976
1977	if( ! fd_devsw_installed ) {
1978		dev = makedev(CDEV_MAJOR, 0);
1979		cdevsw_add(&dev,&fd_cdevsw, NULL);
1980		dev = makedev(BDEV_MAJOR, 0);
1981		bdevsw_add(&dev,&fd_bdevsw, NULL);
1982		fd_devsw_installed = 1;
1983	}
1984}
1985
1986SYSINIT(fddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,fd_drvinit,NULL)
1987
1988#endif
1989/*
1990 * Hello emacs, these are the
1991 * Local Variables:
1992 *  c-indent-level:               8
1993 *  c-continued-statement-offset: 8
1994 *  c-continued-brace-offset:     0
1995 *  c-brace-offset:              -8
1996 *  c-brace-imaginary-offset:     0
1997 *  c-argdecl-indent:             8
1998 *  c-label-offset:              -8
1999 *  c++-hanging-braces:           1
2000 *  c++-access-specifier-offset: -8
2001 *  c++-empty-arglist-indent:     8
2002 *  c++-friend-offset:            0
2003 * End:
2004 */
2005