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