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