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