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