xref: /freebsd/sys/dev/fdc/fdc.c (revision b2be795bf24879ab03d67b003e6436dd48665ad6)
15b81b6b3SRodney W. Grimes /*#define DEBUG 1*/
25b81b6b3SRodney W. Grimes /*-
35b81b6b3SRodney W. Grimes  * Copyright (c) 1990 The Regents of the University of California.
45b81b6b3SRodney W. Grimes  * All rights reserved.
55b81b6b3SRodney W. Grimes  *
65b81b6b3SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
75b81b6b3SRodney W. Grimes  * Don Ahn.
85b81b6b3SRodney W. Grimes  *
95b81b6b3SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
105b81b6b3SRodney W. Grimes  * modification, are permitted provided that the following conditions
115b81b6b3SRodney W. Grimes  * are met:
125b81b6b3SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
135b81b6b3SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
145b81b6b3SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
155b81b6b3SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
165b81b6b3SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
175b81b6b3SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
185b81b6b3SRodney W. Grimes  *    must display the following acknowledgement:
195b81b6b3SRodney W. Grimes  *	This product includes software developed by the University of
205b81b6b3SRodney W. Grimes  *	California, Berkeley and its contributors.
215b81b6b3SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
225b81b6b3SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
235b81b6b3SRodney W. Grimes  *    without specific prior written permission.
245b81b6b3SRodney W. Grimes  *
255b81b6b3SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
265b81b6b3SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
275b81b6b3SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
285b81b6b3SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
295b81b6b3SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
305b81b6b3SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
315b81b6b3SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
325b81b6b3SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
335b81b6b3SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
345b81b6b3SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
355b81b6b3SRodney W. Grimes  * SUCH DAMAGE.
365b81b6b3SRodney W. Grimes  *
37dc4ff321SRodney W. Grimes  *	from:	@(#)fd.c	7.4 (Berkeley) 5/25/91
38b2be795bSAndrey A. Chernov  *	$Id: fd.c,v 1.28 1994/08/23 07:52:09 paul Exp $
395b81b6b3SRodney W. Grimes  *
405b81b6b3SRodney W. Grimes  */
415b81b6b3SRodney W. Grimes 
42b99f0a4aSAndrew Moore #include "ft.h"
43b99f0a4aSAndrew Moore #if NFT < 1
44b99f0a4aSAndrew Moore #undef NFDC
45b99f0a4aSAndrew Moore #endif
465b81b6b3SRodney W. Grimes #include "fd.h"
475b81b6b3SRodney W. Grimes 
48b99f0a4aSAndrew Moore #if NFDC > 0
49b99f0a4aSAndrew Moore 
50b99f0a4aSAndrew Moore #include <sys/param.h>
51b99f0a4aSAndrew Moore #include <sys/dkbad.h>
52b99f0a4aSAndrew Moore #include <sys/systm.h>
53b99f0a4aSAndrew Moore #include <sys/kernel.h>
54b99f0a4aSAndrew Moore #include <sys/conf.h>
55b99f0a4aSAndrew Moore #include <sys/file.h>
56b99f0a4aSAndrew Moore #include <sys/ioctl.h>
57b99f0a4aSAndrew Moore #include <machine/ioctl_fd.h>
58b99f0a4aSAndrew Moore #include <sys/disklabel.h>
59b99f0a4aSAndrew Moore #include <sys/buf.h>
60b99f0a4aSAndrew Moore #include <sys/uio.h>
61b99f0a4aSAndrew Moore #include <sys/malloc.h>
62b99f0a4aSAndrew Moore #include <sys/syslog.h>
63f540b106SGarrett Wollman #include <i386/isa/isa.h>
64f540b106SGarrett Wollman #include <i386/isa/isa_device.h>
65f540b106SGarrett Wollman #include <i386/isa/fdreg.h>
66f540b106SGarrett Wollman #include <i386/isa/fdc.h>
67f540b106SGarrett Wollman #include <i386/isa/icu.h>
68f540b106SGarrett Wollman #include <i386/isa/rtc.h>
695b81b6b3SRodney W. Grimes 
70b99f0a4aSAndrew Moore #if NFT > 0
71b99f0a4aSAndrew Moore extern int ftopen(), ftintr(), ftattach(), ftclose(), ftioctl();
72b99f0a4aSAndrew Moore #endif
735b81b6b3SRodney W. Grimes 
74b2be795bSAndrey A. Chernov #define RAW_PART 2
75b2be795bSAndrey A. Chernov 
765b81b6b3SRodney W. Grimes #define b_cylin b_resid
775b81b6b3SRodney W. Grimes #define FDBLK 512
785b81b6b3SRodney W. Grimes 
79b39c878eSAndrey A. Chernov /* misuse a flag to identify format operation */
80b39c878eSAndrey A. Chernov #define B_FORMAT B_XXX
815b81b6b3SRodney W. Grimes 
82b39c878eSAndrey A. Chernov #define NUMTYPES 14
83b39c878eSAndrey A. Chernov #define NUMDENS  (NUMTYPES - 6)
847ca0641bSAndrey A. Chernov 
85b99f0a4aSAndrew Moore /* This defines (-1) must match index for fd_types */
86b99f0a4aSAndrew Moore #define F_TAPE_TYPE	0x020	/* bit for fd_types to indicate tape */
87b99f0a4aSAndrew Moore #define NO_TYPE		0	/* must match NO_TYPE in ft.c */
88b99f0a4aSAndrew Moore #define FD_1720         1
89b99f0a4aSAndrew Moore #define FD_1480         2
90b99f0a4aSAndrew Moore #define FD_1440         3
91b99f0a4aSAndrew Moore #define FD_1200         4
92b99f0a4aSAndrew Moore #define FD_820          5
93b99f0a4aSAndrew Moore #define FD_800          6
94b99f0a4aSAndrew Moore #define FD_720          7
95b99f0a4aSAndrew Moore #define FD_360          8
96ed2fa05eSAndrey A. Chernov 
97b99f0a4aSAndrew Moore #define FD_1480in5_25   9
98b99f0a4aSAndrew Moore #define FD_1440in5_25   10
99b99f0a4aSAndrew Moore #define FD_820in5_25    11
100b99f0a4aSAndrew Moore #define FD_800in5_25    12
101b99f0a4aSAndrew Moore #define FD_720in5_25    13
102b99f0a4aSAndrew Moore #define FD_360in5_25    14
103b99f0a4aSAndrew Moore 
1047ca0641bSAndrey A. Chernov 
1055b81b6b3SRodney W. Grimes struct fd_type fd_types[NUMTYPES] =
1065b81b6b3SRodney W. Grimes {
107126518a1SAndrey A. Chernov { 21,2,0xFF,0x04,82,3444,1,FDC_500KBPS,2,0x0C,2 }, /* 1.72M in HD 3.5in */
108126518a1SAndrey A. Chernov { 18,2,0xFF,0x1B,82,2952,1,FDC_500KBPS,2,0x6C,1 }, /* 1.48M in HD 3.5in */
109126518a1SAndrey A. Chernov { 18,2,0xFF,0x1B,80,2880,1,FDC_500KBPS,2,0x6C,1 }, /* 1.44M in HD 3.5in */
110126518a1SAndrey A. Chernov { 15,2,0xFF,0x1B,80,2400,1,FDC_500KBPS,2,0x54,1 }, /*  1.2M in HD 5.25/3.5 */
111126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,82,1640,1,FDC_250KBPS,2,0x2E,1 }, /*  820K in HD 3.5in */
112126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,80,1600,1,FDC_250KBPS,2,0x2E,1 }, /*  800K in HD 3.5in */
113126518a1SAndrey A. Chernov {  9,2,0xFF,0x20,80,1440,1,FDC_250KBPS,2,0x50,1 }, /*  720K in HD 3.5in */
114b0568305SAndrey A. Chernov {  9,2,0xFF,0x2A,40, 720,1,FDC_250KBPS,2,0x50,1 }, /*  360K in DD 5.25in */
115ed2fa05eSAndrey A. Chernov 
116126518a1SAndrey A. Chernov { 18,2,0xFF,0x02,82,2952,1,FDC_500KBPS,2,0x02,2 }, /* 1.48M in HD 5.25in */
117126518a1SAndrey A. Chernov { 18,2,0xFF,0x02,80,2880,1,FDC_500KBPS,2,0x02,2 }, /* 1.44M in HD 5.25in */
118126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,82,1640,1,FDC_300KBPS,2,0x2E,1 }, /*  820K in HD 5.25in */
119126518a1SAndrey A. Chernov { 10,2,0xFF,0x10,80,1600,1,FDC_300KBPS,2,0x2E,1 }, /*  800K in HD 5.25in */
120126518a1SAndrey A. Chernov {  9,2,0xFF,0x20,80,1440,1,FDC_300KBPS,2,0x50,1 }, /*  720K in HD 5.25in */
121126518a1SAndrey A. Chernov {  9,2,0xFF,0x23,40, 720,2,FDC_300KBPS,2,0x50,1 }, /*  360K in HD 5.25in */
1225b81b6b3SRodney W. Grimes };
1235b81b6b3SRodney W. Grimes 
124b99f0a4aSAndrew Moore #define DRVS_PER_CTLR 2		/* 2 floppies */
1255b81b6b3SRodney W. Grimes /***********************************************************************\
1265b81b6b3SRodney W. Grimes * Per controller structure.						*
1275b81b6b3SRodney W. Grimes \***********************************************************************/
128b99f0a4aSAndrew Moore struct fdc_data fdc_data[NFDC];
1295b81b6b3SRodney W. Grimes 
1305b81b6b3SRodney W. Grimes /***********************************************************************\
1315b81b6b3SRodney W. Grimes * Per drive structure.							*
132b99f0a4aSAndrew Moore * N per controller  (DRVS_PER_CTLR)					*
1335b81b6b3SRodney W. Grimes \***********************************************************************/
1345b81b6b3SRodney W. Grimes struct fd_data {
135b99f0a4aSAndrew Moore 	struct	fdc_data *fdc;	/* pointer to controller structure */
1365b81b6b3SRodney W. Grimes 	int	fdsu;		/* this units number on this controller */
1375b81b6b3SRodney W. Grimes 	int	type;		/* Drive type (HD, DD     */
1385b81b6b3SRodney W. Grimes 	struct	fd_type *ft;	/* pointer to the type descriptor */
1395b81b6b3SRodney W. Grimes 	int	flags;
1405b81b6b3SRodney W. Grimes #define	FD_OPEN		0x01	/* it's open		*/
1415b81b6b3SRodney W. Grimes #define	FD_ACTIVE	0x02	/* it's active		*/
1425b81b6b3SRodney W. Grimes #define	FD_MOTOR	0x04	/* motor should be on	*/
1435b81b6b3SRodney W. Grimes #define	FD_MOTOR_WAIT	0x08	/* motor coming up	*/
1445b81b6b3SRodney W. Grimes 	int skip;
1455b81b6b3SRodney W. Grimes 	int hddrv;
1465b81b6b3SRodney W. Grimes 	int track;		/* where we think the head is */
1475b81b6b3SRodney W. Grimes } fd_data[NFD];
1485b81b6b3SRodney W. Grimes 
1495b81b6b3SRodney W. Grimes /***********************************************************************\
1505b81b6b3SRodney W. Grimes * Throughout this file the following conventions will be used:		*
1515b81b6b3SRodney W. Grimes * fd is a pointer to the fd_data struct for the drive in question	*
1525b81b6b3SRodney W. Grimes * fdc is a pointer to the fdc_data struct for the controller		*
1535b81b6b3SRodney W. Grimes * fdu is the floppy drive unit number					*
1545b81b6b3SRodney W. Grimes * fdcu is the floppy controller unit number				*
1555b81b6b3SRodney W. Grimes * fdsu is the floppy drive unit number on that controller. (sub-unit)	*
1565b81b6b3SRodney W. Grimes \***********************************************************************/
157b99f0a4aSAndrew Moore 
158b99f0a4aSAndrew Moore #define	id_physid id_scsiid	/* this biotab field doubles as a field */
159b99f0a4aSAndrew Moore 				/* for the physical unit number on the controller */
1605b81b6b3SRodney W. Grimes 
161aaf08d94SGarrett Wollman static int retrier(fdcu_t);
162aaf08d94SGarrett Wollman 
1635b81b6b3SRodney W. Grimes #define DEVIDLE		0
1645b81b6b3SRodney W. Grimes #define FINDWORK	1
1655b81b6b3SRodney W. Grimes #define	DOSEEK		2
1665b81b6b3SRodney W. Grimes #define SEEKCOMPLETE 	3
1675b81b6b3SRodney W. Grimes #define	IOCOMPLETE	4
1685b81b6b3SRodney W. Grimes #define RECALCOMPLETE	5
1695b81b6b3SRodney W. Grimes #define	STARTRECAL	6
1705b81b6b3SRodney W. Grimes #define	RESETCTLR	7
1715b81b6b3SRodney W. Grimes #define	SEEKWAIT	8
1725b81b6b3SRodney W. Grimes #define	RECALWAIT	9
1735b81b6b3SRodney W. Grimes #define	MOTORWAIT	10
1745b81b6b3SRodney W. Grimes #define	IOTIMEDOUT	11
1755b81b6b3SRodney W. Grimes 
1765b81b6b3SRodney W. Grimes #ifdef	DEBUG
1775b81b6b3SRodney W. Grimes char *fdstates[] =
1785b81b6b3SRodney W. Grimes {
1795b81b6b3SRodney W. Grimes "DEVIDLE",
1805b81b6b3SRodney W. Grimes "FINDWORK",
1815b81b6b3SRodney W. Grimes "DOSEEK",
1825b81b6b3SRodney W. Grimes "SEEKCOMPLETE",
1835b81b6b3SRodney W. Grimes "IOCOMPLETE",
1845b81b6b3SRodney W. Grimes "RECALCOMPLETE",
1855b81b6b3SRodney W. Grimes "STARTRECAL",
1865b81b6b3SRodney W. Grimes "RESETCTLR",
1875b81b6b3SRodney W. Grimes "SEEKWAIT",
1885b81b6b3SRodney W. Grimes "RECALWAIT",
1895b81b6b3SRodney W. Grimes "MOTORWAIT",
1905b81b6b3SRodney W. Grimes "IOTIMEDOUT"
1915b81b6b3SRodney W. Grimes };
1925b81b6b3SRodney W. Grimes 
1935b81b6b3SRodney W. Grimes 
1945b81b6b3SRodney W. Grimes int	fd_debug = 1;
1955b81b6b3SRodney W. Grimes #define TRACE0(arg) if(fd_debug) printf(arg)
1965b81b6b3SRodney W. Grimes #define TRACE1(arg1,arg2) if(fd_debug) printf(arg1,arg2)
197381fe1aaSGarrett Wollman #else /* DEBUG */
1985b81b6b3SRodney W. Grimes #define TRACE0(arg)
1995b81b6b3SRodney W. Grimes #define TRACE1(arg1,arg2)
200381fe1aaSGarrett Wollman #endif /* DEBUG */
2015b81b6b3SRodney W. Grimes 
202381fe1aaSGarrett Wollman static void fdstart(fdcu_t);
203381fe1aaSGarrett Wollman void fdintr(fdcu_t);
204d0917939SPaul Richards static timeout_t fd_turnoff;
2055b81b6b3SRodney W. Grimes 
2065b81b6b3SRodney W. Grimes /****************************************************************************/
2075b81b6b3SRodney W. Grimes /*                      autoconfiguration stuff                             */
2085b81b6b3SRodney W. Grimes /****************************************************************************/
209381fe1aaSGarrett Wollman static int fdprobe(struct isa_device *);
210381fe1aaSGarrett Wollman static int fdattach(struct isa_device *);
2115b81b6b3SRodney W. Grimes 
212b99f0a4aSAndrew Moore struct	isa_driver fdcdriver = {
213b99f0a4aSAndrew Moore 	fdprobe, fdattach, "fdc",
2145b81b6b3SRodney W. Grimes };
2155b81b6b3SRodney W. Grimes 
2165b81b6b3SRodney W. Grimes /*
2175b81b6b3SRodney W. Grimes  * probe for existance of controller
2185b81b6b3SRodney W. Grimes  */
219381fe1aaSGarrett Wollman int
2205b81b6b3SRodney W. Grimes fdprobe(dev)
2215b81b6b3SRodney W. Grimes 	struct isa_device *dev;
2225b81b6b3SRodney W. Grimes {
2235b81b6b3SRodney W. Grimes 	fdcu_t	fdcu = dev->id_unit;
2245b81b6b3SRodney W. Grimes 	if(fdc_data[fdcu].flags & FDC_ATTACHED)
2255b81b6b3SRodney W. Grimes 	{
2265b81b6b3SRodney W. Grimes 		printf("fdc: same unit (%d) used multiple times\n",fdcu);
2275b81b6b3SRodney W. Grimes 		return 0;
2285b81b6b3SRodney W. Grimes 	}
2295b81b6b3SRodney W. Grimes 
2305b81b6b3SRodney W. Grimes 	fdc_data[fdcu].baseport = dev->id_iobase;
2315b81b6b3SRodney W. Grimes 
23216111cedSAndrew Moore 	/* First - lets reset the floppy controller */
23316111cedSAndrew Moore 
23416111cedSAndrew Moore 	outb(dev->id_iobase+fdout,0);
23516111cedSAndrew Moore 	DELAY(100);
23616111cedSAndrew Moore 	outb(dev->id_iobase+fdout,FDO_FRST);
23716111cedSAndrew Moore 
2385b81b6b3SRodney W. Grimes 	/* see if it can handle a command */
2395b81b6b3SRodney W. Grimes 	if (out_fdc(fdcu,NE7CMD_SPECIFY) < 0)
2405b81b6b3SRodney W. Grimes 	{
2415b81b6b3SRodney W. Grimes 		return(0);
2425b81b6b3SRodney W. Grimes 	}
2435b81b6b3SRodney W. Grimes 	out_fdc(fdcu,0xDF);
2445b81b6b3SRodney W. Grimes 	out_fdc(fdcu,2);
2455b81b6b3SRodney W. Grimes 	return (IO_FDCSIZE);
2465b81b6b3SRodney W. Grimes }
2475b81b6b3SRodney W. Grimes 
2485b81b6b3SRodney W. Grimes /*
2495b81b6b3SRodney W. Grimes  * wire controller into system, look for floppy units
2505b81b6b3SRodney W. Grimes  */
251381fe1aaSGarrett Wollman int
2525b81b6b3SRodney W. Grimes fdattach(dev)
2535b81b6b3SRodney W. Grimes 	struct isa_device *dev;
2545b81b6b3SRodney W. Grimes {
2555b81b6b3SRodney W. Grimes 	unsigned fdt,st0, cyl;
2565b81b6b3SRodney W. Grimes 	int	hdr;
2575b81b6b3SRodney W. Grimes 	fdu_t	fdu;
2585b81b6b3SRodney W. Grimes 	fdcu_t	fdcu = dev->id_unit;
2595b81b6b3SRodney W. Grimes 	fdc_p	fdc = fdc_data + fdcu;
2605b81b6b3SRodney W. Grimes 	fd_p	fd;
2615b81b6b3SRodney W. Grimes 	int	fdsu;
262b99f0a4aSAndrew Moore 	struct isa_device *fdup;
2635b81b6b3SRodney W. Grimes 
2645b81b6b3SRodney W. Grimes 	fdc->fdcu = fdcu;
2655b81b6b3SRodney W. Grimes 	fdc->flags |= FDC_ATTACHED;
2665b81b6b3SRodney W. Grimes 	fdc->dmachan = dev->id_drq;
2675b81b6b3SRodney W. Grimes 	fdc->state = DEVIDLE;
2685b81b6b3SRodney W. Grimes 	hdr = 0;
269b99f0a4aSAndrew Moore 	printf("fdc%d:", fdcu);
2705b81b6b3SRodney W. Grimes 
2715b81b6b3SRodney W. Grimes 	/* check for each floppy drive */
272b99f0a4aSAndrew Moore 	for (fdup = isa_biotab_fdc; fdup->id_driver != 0; fdup++) {
273b99f0a4aSAndrew Moore 		if (fdup->id_iobase != dev->id_iobase)
274b99f0a4aSAndrew Moore 			continue;
275b99f0a4aSAndrew Moore 		fdu = fdup->id_unit;
276b99f0a4aSAndrew Moore 		fd = &fd_data[fdu];
277b99f0a4aSAndrew Moore 		if (fdu >= (NFD+NFT))
278b99f0a4aSAndrew Moore 			continue;
279b99f0a4aSAndrew Moore 		fdsu = fdup->id_physid;
280b99f0a4aSAndrew Moore 				/* look up what bios thinks we have */
281b99f0a4aSAndrew Moore 		switch (fdu) {
282b99f0a4aSAndrew Moore 			case 0: fdt = (rtcin(RTC_FDISKETTE) & 0xf0);
283b99f0a4aSAndrew Moore 				break;
284b99f0a4aSAndrew Moore 			case 1: fdt = ((rtcin(RTC_FDISKETTE) << 4) & 0xf0);
285b99f0a4aSAndrew Moore 				break;
286b99f0a4aSAndrew Moore 			default: fdt = RTCFDT_NONE;
287b99f0a4aSAndrew Moore 				break;
288b99f0a4aSAndrew Moore 		}
2895b81b6b3SRodney W. Grimes 		/* is there a unit? */
290b99f0a4aSAndrew Moore 		if ((fdt == RTCFDT_NONE)
291b99f0a4aSAndrew Moore #if NFT > 0
292b99f0a4aSAndrew Moore 		|| (fdsu >= DRVS_PER_CTLR)) {
293b99f0a4aSAndrew Moore #else
294b99f0a4aSAndrew Moore 		) {
29556ef0285SAndrew Moore 			fd->type = NO_TYPE;
296b99f0a4aSAndrew Moore #endif
297b99f0a4aSAndrew Moore #if NFT > 0
298b99f0a4aSAndrew Moore 				/* If BIOS says no floppy, or > 2nd device */
299b99f0a4aSAndrew Moore 				/* Probe for and attach a floppy tape.     */
300b99f0a4aSAndrew Moore 			if (ftattach(dev, fdup))
301b99f0a4aSAndrew Moore 				continue;
30256ef0285SAndrew Moore 			if (fdsu < DRVS_PER_CTLR)
303b99f0a4aSAndrew Moore 				fd->type = NO_TYPE;
30456ef0285SAndrew Moore #endif
3055b81b6b3SRodney W. Grimes 			continue;
306f5f7ba03SJordan K. Hubbard 		}
3075b81b6b3SRodney W. Grimes 
3085b81b6b3SRodney W. Grimes #ifdef notyet
3095b81b6b3SRodney W. Grimes 		/* select it */
3105b81b6b3SRodney W. Grimes 		fd_turnon1(fdu);
3115b81b6b3SRodney W. Grimes 		spinwait(1000);	/* 1 sec */
3125b81b6b3SRodney W. Grimes 		out_fdc(fdcu,NE7CMD_RECAL);	/* Recalibrate Function */
3135b81b6b3SRodney W. Grimes 		out_fdc(fdcu,fdsu);
3145b81b6b3SRodney W. Grimes 		spinwait(1000);	/* 1 sec */
3155b81b6b3SRodney W. Grimes 
3165b81b6b3SRodney W. Grimes 		/* anything responding */
3175b81b6b3SRodney W. Grimes 		out_fdc(fdcu,NE7CMD_SENSEI);
3185b81b6b3SRodney W. Grimes 		st0 = in_fdc(fdcu);
3195b81b6b3SRodney W. Grimes 		cyl = in_fdc(fdcu);
3205b81b6b3SRodney W. Grimes 		if (st0 & 0xd0)
3215b81b6b3SRodney W. Grimes 			continue;
3225b81b6b3SRodney W. Grimes 
3235b81b6b3SRodney W. Grimes #endif
324b99f0a4aSAndrew Moore 		fd->track = -2;
325b99f0a4aSAndrew Moore 		fd->fdc = fdc;
326b99f0a4aSAndrew Moore 		fd->fdsu = fdsu;
327b99f0a4aSAndrew Moore 		printf(" [%d: fd%d: ", fdsu, fdu);
3285b81b6b3SRodney W. Grimes 
329b99f0a4aSAndrew Moore 		switch (fdt) {
3307ca0641bSAndrey A. Chernov 		case RTCFDT_12M:
331b99f0a4aSAndrew Moore 			printf("1.2MB 5.25in]");
332b99f0a4aSAndrew Moore 			fd->type = FD_1200;
3337ca0641bSAndrey A. Chernov 			break;
3347ca0641bSAndrey A. Chernov 		case RTCFDT_144M:
335b99f0a4aSAndrew Moore 			printf("1.44MB 3.5in]");
336b99f0a4aSAndrew Moore 			fd->type = FD_1440;
3377ca0641bSAndrey A. Chernov 			break;
3387ca0641bSAndrey A. Chernov 		case RTCFDT_360K:
339b99f0a4aSAndrew Moore 			printf("360KB 5.25in]");
340b99f0a4aSAndrew Moore 			fd->type = FD_360;
3417ca0641bSAndrey A. Chernov 			break;
342ed2fa05eSAndrey A. Chernov 		case RTCFDT_720K:
343b99f0a4aSAndrew Moore 			printf("720KB 3.5in]");
344b99f0a4aSAndrew Moore 			fd->type = FD_720;
345ed2fa05eSAndrey A. Chernov 			break;
3467ca0641bSAndrey A. Chernov 		default:
347b99f0a4aSAndrew Moore 			printf("unknown]");
348b99f0a4aSAndrew Moore 			fd->type = NO_TYPE;
3497ca0641bSAndrey A. Chernov 			break;
3505b81b6b3SRodney W. Grimes 		}
3515b81b6b3SRodney W. Grimes 
35226f9a767SRodney W. Grimes 		fd_turnoff((caddr_t)fdu);
3535b81b6b3SRodney W. Grimes 		hdr = 1;
3545b81b6b3SRodney W. Grimes 	}
355b99f0a4aSAndrew Moore 	printf("\n");
3565b81b6b3SRodney W. Grimes 
3575b81b6b3SRodney W. Grimes 	/* Set transfer to 500kbps */
3585b81b6b3SRodney W. Grimes 	outb(fdc->baseport+fdctl,0); /*XXX*/
359381fe1aaSGarrett Wollman 	return 1;
3605b81b6b3SRodney W. Grimes }
3615b81b6b3SRodney W. Grimes 
3625b81b6b3SRodney W. Grimes int
3635b81b6b3SRodney W. Grimes fdsize(dev)
3645b81b6b3SRodney W. Grimes 	dev_t	dev;
3655b81b6b3SRodney W. Grimes {
3665b81b6b3SRodney W. Grimes 	return(0);
3675b81b6b3SRodney W. Grimes }
3685b81b6b3SRodney W. Grimes 
3695b81b6b3SRodney W. Grimes /****************************************************************************/
3705b81b6b3SRodney W. Grimes /*                               fdstrategy                                 */
3715b81b6b3SRodney W. Grimes /****************************************************************************/
372381fe1aaSGarrett Wollman void fdstrategy(struct buf *bp)
3735b81b6b3SRodney W. Grimes {
3745b81b6b3SRodney W. Grimes 	register struct buf *dp,*dp0,*dp1;
3755b81b6b3SRodney W. Grimes 	long nblocks,blknum;
3765b81b6b3SRodney W. Grimes  	int	s;
3775b81b6b3SRodney W. Grimes  	fdcu_t	fdcu;
3785b81b6b3SRodney W. Grimes  	fdu_t	fdu;
3795b81b6b3SRodney W. Grimes  	fdc_p	fdc;
3805b81b6b3SRodney W. Grimes  	fd_p	fd;
3815b81b6b3SRodney W. Grimes 
3825b81b6b3SRodney W. Grimes  	fdu = FDUNIT(minor(bp->b_dev));
3835b81b6b3SRodney W. Grimes 	fd = &fd_data[fdu];
3845b81b6b3SRodney W. Grimes 	fdc = fd->fdc;
3855b81b6b3SRodney W. Grimes 	fdcu = fdc->fdcu;
3865b81b6b3SRodney W. Grimes 
387b99f0a4aSAndrew Moore #if NFT > 0
388b99f0a4aSAndrew Moore 	/* check for controller already busy with tape */
389b99f0a4aSAndrew Moore 	if (fdc->flags & FDC_TAPE_BUSY) {
390b99f0a4aSAndrew Moore 		bp->b_error = EBUSY;
391b99f0a4aSAndrew Moore 		bp->b_flags |= B_ERROR;
392b99f0a4aSAndrew Moore 		return;
393b99f0a4aSAndrew Moore 		}
394b99f0a4aSAndrew Moore #endif
395a60eff27SNate Williams 	if ((fdu >= NFD) || (bp->b_blkno < 0)) {
3965b81b6b3SRodney W. Grimes 		printf("fdstrat: fdu = %d, blkno = %d, bcount = %d\n",
3975b81b6b3SRodney W. Grimes 			fdu, bp->b_blkno, bp->b_bcount);
3985b81b6b3SRodney W. Grimes 		pg("fd:error in fdstrategy");
3995b81b6b3SRodney W. Grimes 		bp->b_error = EINVAL;
4005b81b6b3SRodney W. Grimes 		bp->b_flags |= B_ERROR;
4015b81b6b3SRodney W. Grimes 		goto bad;
4025b81b6b3SRodney W. Grimes 	}
4035b81b6b3SRodney W. Grimes 	/*
4045b81b6b3SRodney W. Grimes 	 * Set up block calculations.
4055b81b6b3SRodney W. Grimes 	 */
4065b81b6b3SRodney W. Grimes 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
4075b81b6b3SRodney W. Grimes  	nblocks = fd->ft->size;
4085b81b6b3SRodney W. Grimes 	if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
4095b81b6b3SRodney W. Grimes 		if (blknum == nblocks) {
4105b81b6b3SRodney W. Grimes 			bp->b_resid = bp->b_bcount;
4115b81b6b3SRodney W. Grimes 		} else {
4125b81b6b3SRodney W. Grimes 			bp->b_error = ENOSPC;
4135b81b6b3SRodney W. Grimes 			bp->b_flags |= B_ERROR;
4145b81b6b3SRodney W. Grimes 		}
4155b81b6b3SRodney W. Grimes 		goto bad;
4165b81b6b3SRodney W. Grimes 	}
4175b81b6b3SRodney W. Grimes  	bp->b_cylin = blknum / (fd->ft->sectrac * fd->ft->heads);
4180e195446SDavid Greenman 	bp->b_pblkno = bp->b_blkno;
4195b81b6b3SRodney W. Grimes 	dp = &(fdc->head);
4205b81b6b3SRodney W. Grimes 	s = splbio();
4215b81b6b3SRodney W. Grimes 	disksort(dp, bp);
422d0917939SPaul Richards 	untimeout(fd_turnoff, (caddr_t)fdu); /* a good idea */
4235b81b6b3SRodney W. Grimes 	fdstart(fdcu);
4245b81b6b3SRodney W. Grimes 	splx(s);
4255b81b6b3SRodney W. Grimes 	return;
4265b81b6b3SRodney W. Grimes 
4275b81b6b3SRodney W. Grimes bad:
4285b81b6b3SRodney W. Grimes 	biodone(bp);
429b39c878eSAndrey A. Chernov 	return;
4305b81b6b3SRodney W. Grimes }
4315b81b6b3SRodney W. Grimes 
4325b81b6b3SRodney W. Grimes /****************************************************************************/
4335b81b6b3SRodney W. Grimes /*                            motor control stuff                           */
4345b81b6b3SRodney W. Grimes /*		remember to not deselect the drive we're working on         */
4355b81b6b3SRodney W. Grimes /****************************************************************************/
436381fe1aaSGarrett Wollman void
437f5f7ba03SJordan K. Hubbard set_motor(fdcu, fdu, reset)
438f5f7ba03SJordan K. Hubbard 	fdcu_t fdcu;
439f5f7ba03SJordan K. Hubbard 	fdu_t fdu;
440f5f7ba03SJordan K. Hubbard 	int reset;
4415b81b6b3SRodney W. Grimes {
4425b81b6b3SRodney W. Grimes 	int m0,m1;
4435b81b6b3SRodney W. Grimes 	int selunit;
4445b81b6b3SRodney W. Grimes 	fd_p fd;
4455b81b6b3SRodney W. Grimes 	if(fd = fdc_data[fdcu].fd)/* yes an assign! */
4465b81b6b3SRodney W. Grimes 	{
4475b81b6b3SRodney W. Grimes 		selunit =  fd->fdsu;
4485b81b6b3SRodney W. Grimes 	}
4495b81b6b3SRodney W. Grimes 	else
4505b81b6b3SRodney W. Grimes 	{
4515b81b6b3SRodney W. Grimes 		selunit = 0;
4525b81b6b3SRodney W. Grimes 	}
4535b81b6b3SRodney W. Grimes 	m0 = fd_data[fdcu * DRVS_PER_CTLR + 0].flags & FD_MOTOR;
4545b81b6b3SRodney W. Grimes 	m1 = fd_data[fdcu * DRVS_PER_CTLR + 1].flags & FD_MOTOR;
4555b81b6b3SRodney W. Grimes 	outb(fdc_data[fdcu].baseport+fdout,
4565b81b6b3SRodney W. Grimes 		selunit
4575b81b6b3SRodney W. Grimes 		| (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
4585b81b6b3SRodney W. Grimes 		| (m0 ? FDO_MOEN0 : 0)
4595b81b6b3SRodney W. Grimes 		| (m1 ? FDO_MOEN1 : 0));
4605b81b6b3SRodney W. Grimes 	TRACE1("[0x%x->fdout]",(
4615b81b6b3SRodney W. Grimes 		selunit
4625b81b6b3SRodney W. Grimes 		| (reset ? 0 : (FDO_FRST|FDO_FDMAEN))
4635b81b6b3SRodney W. Grimes 		| (m0 ? FDO_MOEN0 : 0)
4645b81b6b3SRodney W. Grimes 		| (m1 ? FDO_MOEN1 : 0)));
4655b81b6b3SRodney W. Grimes }
4665b81b6b3SRodney W. Grimes 
467381fe1aaSGarrett Wollman static void
468d0917939SPaul Richards fd_turnoff(void *arg1)
4695b81b6b3SRodney W. Grimes {
470381fe1aaSGarrett Wollman 	fdu_t fdu = (fdu_t)arg1;
471f5f7ba03SJordan K. Hubbard 	int	s;
472f5f7ba03SJordan K. Hubbard 
4735b81b6b3SRodney W. Grimes 	fd_p fd = fd_data + fdu;
474f5f7ba03SJordan K. Hubbard 	s = splbio();
4755b81b6b3SRodney W. Grimes 	fd->flags &= ~FD_MOTOR;
4765b81b6b3SRodney W. Grimes 	set_motor(fd->fdc->fdcu,fd->fdsu,0);
477f5f7ba03SJordan K. Hubbard 	splx(s);
4785b81b6b3SRodney W. Grimes }
4795b81b6b3SRodney W. Grimes 
480381fe1aaSGarrett Wollman void
481d0917939SPaul Richards fd_motor_on(void *arg1)
4825b81b6b3SRodney W. Grimes {
483381fe1aaSGarrett Wollman 	fdu_t fdu = (fdu_t)arg1;
484f5f7ba03SJordan K. Hubbard 	int	s;
485f5f7ba03SJordan K. Hubbard 
4865b81b6b3SRodney W. Grimes 	fd_p fd = fd_data + fdu;
487f5f7ba03SJordan K. Hubbard 	s = splbio();
4885b81b6b3SRodney W. Grimes 	fd->flags &= ~FD_MOTOR_WAIT;
4895b81b6b3SRodney W. Grimes 	if((fd->fdc->fd == fd) && (fd->fdc->state == MOTORWAIT))
4905b81b6b3SRodney W. Grimes 	{
491f5f7ba03SJordan K. Hubbard 		fdintr(fd->fdc->fdcu);
4925b81b6b3SRodney W. Grimes 	}
493f5f7ba03SJordan K. Hubbard 	splx(s);
4945b81b6b3SRodney W. Grimes }
4955b81b6b3SRodney W. Grimes 
496381fe1aaSGarrett Wollman static void fd_turnon1(fdu_t);
497381fe1aaSGarrett Wollman 
498381fe1aaSGarrett Wollman void
499f5f7ba03SJordan K. Hubbard fd_turnon(fdu)
500f5f7ba03SJordan K. Hubbard 	fdu_t fdu;
5015b81b6b3SRodney W. Grimes {
5025b81b6b3SRodney W. Grimes 	fd_p fd = fd_data + fdu;
5035b81b6b3SRodney W. Grimes 	if(!(fd->flags & FD_MOTOR))
5045b81b6b3SRodney W. Grimes 	{
5055b81b6b3SRodney W. Grimes 		fd_turnon1(fdu);
5065b81b6b3SRodney W. Grimes 		fd->flags |= FD_MOTOR_WAIT;
507d0917939SPaul Richards 		timeout(fd_motor_on, (caddr_t)fdu, hz); /* in 1 sec its ok */
5085b81b6b3SRodney W. Grimes 	}
5095b81b6b3SRodney W. Grimes }
5105b81b6b3SRodney W. Grimes 
511381fe1aaSGarrett Wollman static void
512381fe1aaSGarrett Wollman fd_turnon1(fdu_t fdu)
5135b81b6b3SRodney W. Grimes {
5145b81b6b3SRodney W. Grimes 	fd_p fd = fd_data + fdu;
5155b81b6b3SRodney W. Grimes 	fd->flags |= FD_MOTOR;
5165b81b6b3SRodney W. Grimes 	set_motor(fd->fdc->fdcu,fd->fdsu,0);
5175b81b6b3SRodney W. Grimes }
5185b81b6b3SRodney W. Grimes 
5195b81b6b3SRodney W. Grimes /****************************************************************************/
5205b81b6b3SRodney W. Grimes /*                             fdc in/out                                   */
5215b81b6b3SRodney W. Grimes /****************************************************************************/
5225b81b6b3SRodney W. Grimes int
523f5f7ba03SJordan K. Hubbard in_fdc(fdcu)
524f5f7ba03SJordan K. Hubbard 	fdcu_t fdcu;
5255b81b6b3SRodney W. Grimes {
5265b81b6b3SRodney W. Grimes 	int baseport = fdc_data[fdcu].baseport;
5275b81b6b3SRodney W. Grimes 	int i, j = 100000;
5285b81b6b3SRodney W. Grimes 	while ((i = inb(baseport+fdsts) & (NE7_DIO|NE7_RQM))
5295b81b6b3SRodney W. Grimes 		!= (NE7_DIO|NE7_RQM) && j-- > 0)
5305b81b6b3SRodney W. Grimes 		if (i == NE7_RQM) return -1;
5315b81b6b3SRodney W. Grimes 	if (j <= 0)
5325b81b6b3SRodney W. Grimes 		return(-1);
5335b81b6b3SRodney W. Grimes #ifdef	DEBUG
5345b81b6b3SRodney W. Grimes 	i = inb(baseport+fddata);
5355b81b6b3SRodney W. Grimes 	TRACE1("[fddata->0x%x]",(unsigned char)i);
5365b81b6b3SRodney W. Grimes 	return(i);
5375b81b6b3SRodney W. Grimes #else
5385b81b6b3SRodney W. Grimes 	return inb(baseport+fddata);
5395b81b6b3SRodney W. Grimes #endif
5405b81b6b3SRodney W. Grimes }
5415b81b6b3SRodney W. Grimes 
542381fe1aaSGarrett Wollman int
543f5f7ba03SJordan K. Hubbard out_fdc(fdcu, x)
544f5f7ba03SJordan K. Hubbard 	fdcu_t fdcu;
545f5f7ba03SJordan K. Hubbard 	int x;
5465b81b6b3SRodney W. Grimes {
5475b81b6b3SRodney W. Grimes 	int baseport = fdc_data[fdcu].baseport;
5483b3837dbSRodney W. Grimes 	int i;
5495b81b6b3SRodney W. Grimes 
5503b3837dbSRodney W. Grimes 	/* Check that the direction bit is set */
5513b3837dbSRodney W. Grimes 	i = 100000;
5525b81b6b3SRodney W. Grimes 	while ((inb(baseport+fdsts) & NE7_DIO) && i-- > 0);
5533b3837dbSRodney W. Grimes 	if (i <= 0) return (-1);	/* Floppy timed out */
5543b3837dbSRodney W. Grimes 
5553b3837dbSRodney W. Grimes 	/* Check that the floppy controller is ready for a command */
5563b3837dbSRodney W. Grimes 	i = 100000;
5575b81b6b3SRodney W. Grimes 	while ((inb(baseport+fdsts) & NE7_RQM) == 0 && i-- > 0);
5583b3837dbSRodney W. Grimes 	if (i <= 0) return (-1);	/* Floppy timed out */
5593b3837dbSRodney W. Grimes 
5603b3837dbSRodney W. Grimes 	/* Send the command and return */
5615b81b6b3SRodney W. Grimes 	outb(baseport+fddata,x);
5625b81b6b3SRodney W. Grimes 	TRACE1("[0x%x->fddata]",x);
5635b81b6b3SRodney W. Grimes 	return (0);
5645b81b6b3SRodney W. Grimes }
5655b81b6b3SRodney W. Grimes 
5665b81b6b3SRodney W. Grimes /****************************************************************************/
5675b81b6b3SRodney W. Grimes /*                           fdopen/fdclose                                 */
5685b81b6b3SRodney W. Grimes /****************************************************************************/
569381fe1aaSGarrett Wollman int
5705b81b6b3SRodney W. Grimes Fdopen(dev, flags)
5715b81b6b3SRodney W. Grimes 	dev_t	dev;
5725b81b6b3SRodney W. Grimes 	int	flags;
5735b81b6b3SRodney W. Grimes {
5745b81b6b3SRodney W. Grimes  	fdu_t fdu = FDUNIT(minor(dev));
57520a29168SAndrey A. Chernov 	int type = FDTYPE(minor(dev));
576b99f0a4aSAndrew Moore 	fdc_p	fdc;
5775b81b6b3SRodney W. Grimes 
578b99f0a4aSAndrew Moore #if NFT > 0
579b99f0a4aSAndrew Moore 	/* check for a tape open */
580b99f0a4aSAndrew Moore 	if (type & F_TAPE_TYPE)
581b99f0a4aSAndrew Moore 		return(ftopen(dev, flags));
582b99f0a4aSAndrew Moore #endif
5835b81b6b3SRodney W. Grimes 	/* check bounds */
584b99f0a4aSAndrew Moore 	if (fdu >= NFD)
585b99f0a4aSAndrew Moore 		return(ENXIO);
586b99f0a4aSAndrew Moore 	fdc = fd_data[fdu].fdc;
587b99f0a4aSAndrew Moore 	if ((fdc == NULL) || (fd_data[fdu].type == NO_TYPE))
588b99f0a4aSAndrew Moore 		return(ENXIO);
589b99f0a4aSAndrew Moore 	if (type > NUMDENS)
590b99f0a4aSAndrew Moore 		return(ENXIO);
5917ca0641bSAndrey A. Chernov 	if (type == 0)
5927ca0641bSAndrey A. Chernov 		type = fd_data[fdu].type;
5937ca0641bSAndrey A. Chernov 	else {
5947ca0641bSAndrey A. Chernov 		if (type != fd_data[fdu].type) {
595fa4700b4SAndrey A. Chernov 			switch (fd_data[fdu].type) {
5967ca0641bSAndrey A. Chernov 			case FD_360:
5977ca0641bSAndrey A. Chernov 				return(ENXIO);
598ed2fa05eSAndrey A. Chernov 			case FD_720:
599b39c878eSAndrey A. Chernov 				if (   type != FD_820
600b39c878eSAndrey A. Chernov 				    && type != FD_800
601ed2fa05eSAndrey A. Chernov 				   )
602ed2fa05eSAndrey A. Chernov 					return(ENXIO);
603ed2fa05eSAndrey A. Chernov 				break;
6047ca0641bSAndrey A. Chernov 			case FD_1200:
605b39c878eSAndrey A. Chernov 				switch (type) {
606b39c878eSAndrey A. Chernov 				case FD_1480:
607b39c878eSAndrey A. Chernov 					type = FD_1480in5_25;
608fa4700b4SAndrey A. Chernov 					break;
6097ca0641bSAndrey A. Chernov 				case FD_1440:
610b39c878eSAndrey A. Chernov 					type = FD_1440in5_25;
611b39c878eSAndrey A. Chernov 					break;
612b39c878eSAndrey A. Chernov 				case FD_820:
613b39c878eSAndrey A. Chernov 					type = FD_820in5_25;
614b39c878eSAndrey A. Chernov 					break;
615b39c878eSAndrey A. Chernov 				case FD_800:
616b39c878eSAndrey A. Chernov 					type = FD_800in5_25;
617b39c878eSAndrey A. Chernov 					break;
618b39c878eSAndrey A. Chernov 				case FD_720:
619b39c878eSAndrey A. Chernov 					type = FD_720in5_25;
620b39c878eSAndrey A. Chernov 					break;
621b39c878eSAndrey A. Chernov 				case FD_360:
622b39c878eSAndrey A. Chernov 					type = FD_360in5_25;
623b39c878eSAndrey A. Chernov 					break;
624b39c878eSAndrey A. Chernov 				default:
625b39c878eSAndrey A. Chernov 					return(ENXIO);
626b39c878eSAndrey A. Chernov 				}
627b39c878eSAndrey A. Chernov 				break;
628b39c878eSAndrey A. Chernov 			case FD_1440:
629b39c878eSAndrey A. Chernov 				if (   type != FD_1720
630b39c878eSAndrey A. Chernov 				    && type != FD_1480
631ed2fa05eSAndrey A. Chernov 				    && type != FD_1200
632b39c878eSAndrey A. Chernov 				    && type != FD_820
633b39c878eSAndrey A. Chernov 				    && type != FD_800
634b39c878eSAndrey A. Chernov 				    && type != FD_720
6357ca0641bSAndrey A. Chernov 				    )
636dffff499SAndrey A. Chernov 					return(ENXIO);
637fa4700b4SAndrey A. Chernov 				break;
6387ca0641bSAndrey A. Chernov 			}
6397ca0641bSAndrey A. Chernov 		}
640fa4700b4SAndrey A. Chernov 	}
641b99f0a4aSAndrew Moore 	fd_data[fdu].ft = fd_types + type - 1;
6425b81b6b3SRodney W. Grimes 	fd_data[fdu].flags |= FD_OPEN;
6435b81b6b3SRodney W. Grimes 
6445b81b6b3SRodney W. Grimes 	return 0;
6455b81b6b3SRodney W. Grimes }
6465b81b6b3SRodney W. Grimes 
647381fe1aaSGarrett Wollman int
6485b81b6b3SRodney W. Grimes fdclose(dev, flags)
6495b81b6b3SRodney W. Grimes 	dev_t dev;
650381fe1aaSGarrett Wollman 	int flags;
6515b81b6b3SRodney W. Grimes {
6525b81b6b3SRodney W. Grimes  	fdu_t fdu = FDUNIT(minor(dev));
653b99f0a4aSAndrew Moore 	int type = FDTYPE(minor(dev));
654b99f0a4aSAndrew Moore 
655b99f0a4aSAndrew Moore #if NFT > 0
656b99f0a4aSAndrew Moore 	if (type & F_TAPE_TYPE)
657b99f0a4aSAndrew Moore 		return ftclose(0);
658b99f0a4aSAndrew Moore #endif
6595b81b6b3SRodney W. Grimes 	fd_data[fdu].flags &= ~FD_OPEN;
6605b81b6b3SRodney W. Grimes 	return(0);
6615b81b6b3SRodney W. Grimes }
6625b81b6b3SRodney W. Grimes 
6635b81b6b3SRodney W. Grimes 
6645b81b6b3SRodney W. Grimes /***************************************************************\
6655b81b6b3SRodney W. Grimes *				fdstart				*
6665b81b6b3SRodney W. Grimes * We have just queued something.. if the controller is not busy	*
6675b81b6b3SRodney W. Grimes * then simulate the case where it has just finished a command	*
6685b81b6b3SRodney W. Grimes * So that it (the interrupt routine) looks on the queue for more*
6695b81b6b3SRodney W. Grimes * work to do and picks up what we just added.			*
6705b81b6b3SRodney W. Grimes * If the controller is already busy, we need do nothing, as it	*
6715b81b6b3SRodney W. Grimes * will pick up our work when the present work completes		*
6725b81b6b3SRodney W. Grimes \***************************************************************/
673381fe1aaSGarrett Wollman static void
674f5f7ba03SJordan K. Hubbard fdstart(fdcu)
675f5f7ba03SJordan K. Hubbard 	fdcu_t fdcu;
6765b81b6b3SRodney W. Grimes {
6775b81b6b3SRodney W. Grimes 	register struct buf *dp,*bp;
6785b81b6b3SRodney W. Grimes 	int s;
6795b81b6b3SRodney W. Grimes  	fdu_t fdu;
6805b81b6b3SRodney W. Grimes 
6815b81b6b3SRodney W. Grimes 	s = splbio();
6825b81b6b3SRodney W. Grimes 	if(fdc_data[fdcu].state == DEVIDLE)
6835b81b6b3SRodney W. Grimes 	{
6845b81b6b3SRodney W. Grimes 		fdintr(fdcu);
6855b81b6b3SRodney W. Grimes 	}
6865b81b6b3SRodney W. Grimes 	splx(s);
6875b81b6b3SRodney W. Grimes }
6885b81b6b3SRodney W. Grimes 
689381fe1aaSGarrett Wollman static void
690d0917939SPaul Richards fd_timeout(void *arg1)
6915b81b6b3SRodney W. Grimes {
692381fe1aaSGarrett Wollman 	fdcu_t fdcu = (fdcu_t)arg1;
6935b81b6b3SRodney W. Grimes 	fdu_t fdu = fdc_data[fdcu].fdu;
6945b81b6b3SRodney W. Grimes 	int st0, st3, cyl;
6955b81b6b3SRodney W. Grimes 	struct buf *dp,*bp;
696f5f7ba03SJordan K. Hubbard 	int	s;
6975b81b6b3SRodney W. Grimes 
6985b81b6b3SRodney W. Grimes 	dp = &fdc_data[fdcu].head;
699f5f7ba03SJordan K. Hubbard 	s = splbio();
7005b81b6b3SRodney W. Grimes 	bp = dp->b_actf;
7015b81b6b3SRodney W. Grimes 
7025b81b6b3SRodney W. Grimes 	out_fdc(fdcu,NE7CMD_SENSED);
7035b81b6b3SRodney W. Grimes 	out_fdc(fdcu,fd_data[fdu].hddrv);
7045b81b6b3SRodney W. Grimes 	st3 = in_fdc(fdcu);
7055b81b6b3SRodney W. Grimes 
7065b81b6b3SRodney W. Grimes 	out_fdc(fdcu,NE7CMD_SENSEI);
7075b81b6b3SRodney W. Grimes 	st0 = in_fdc(fdcu);
7085b81b6b3SRodney W. Grimes 	cyl = in_fdc(fdcu);
7095b81b6b3SRodney W. Grimes 	printf("fd%d: Operation timeout ST0 %b cyl %d ST3 %b\n",
7105b81b6b3SRodney W. Grimes 			fdu,
7115b81b6b3SRodney W. Grimes 			st0,
7125b81b6b3SRodney W. Grimes 			NE7_ST0BITS,
7135b81b6b3SRodney W. Grimes 			cyl,
7145b81b6b3SRodney W. Grimes 			st3,
7155b81b6b3SRodney W. Grimes 			NE7_ST3BITS);
7165b81b6b3SRodney W. Grimes 
7175b81b6b3SRodney W. Grimes 	if (bp)
7185b81b6b3SRodney W. Grimes 	{
7195b81b6b3SRodney W. Grimes 		retrier(fdcu);
7205b81b6b3SRodney W. Grimes 		fdc_data[fdcu].status[0] = 0xc0;
7215b81b6b3SRodney W. Grimes 		fdc_data[fdcu].state = IOTIMEDOUT;
7225b81b6b3SRodney W. Grimes 		if( fdc_data[fdcu].retry < 6)
7235b81b6b3SRodney W. Grimes 			fdc_data[fdcu].retry = 6;
7245b81b6b3SRodney W. Grimes 	}
7255b81b6b3SRodney W. Grimes 	else
7265b81b6b3SRodney W. Grimes 	{
7275b81b6b3SRodney W. Grimes 		fdc_data[fdcu].fd = (fd_p) 0;
7285b81b6b3SRodney W. Grimes 		fdc_data[fdcu].fdu = -1;
7295b81b6b3SRodney W. Grimes 		fdc_data[fdcu].state = DEVIDLE;
7305b81b6b3SRodney W. Grimes 	}
731f5f7ba03SJordan K. Hubbard 	fdintr(fdcu);
732f5f7ba03SJordan K. Hubbard 	splx(s);
7335b81b6b3SRodney W. Grimes }
7345b81b6b3SRodney W. Grimes 
7355b81b6b3SRodney W. Grimes /* just ensure it has the right spl */
736381fe1aaSGarrett Wollman static void
737d0917939SPaul Richards fd_pseudointr(void *arg1)
7385b81b6b3SRodney W. Grimes {
739381fe1aaSGarrett Wollman 	fdcu_t fdcu = (fdcu_t)arg1;
7405b81b6b3SRodney W. Grimes 	int	s;
7415b81b6b3SRodney W. Grimes 	s = splbio();
7425b81b6b3SRodney W. Grimes 	fdintr(fdcu);
7435b81b6b3SRodney W. Grimes 	splx(s);
7445b81b6b3SRodney W. Grimes }
7455b81b6b3SRodney W. Grimes 
7465b81b6b3SRodney W. Grimes /***********************************************************************\
7475b81b6b3SRodney W. Grimes *                                 fdintr				*
7485b81b6b3SRodney W. Grimes * keep calling the state machine until it returns a 0			*
7495b81b6b3SRodney W. Grimes * ALWAYS called at SPLBIO 						*
7505b81b6b3SRodney W. Grimes \***********************************************************************/
751381fe1aaSGarrett Wollman void
752381fe1aaSGarrett Wollman fdintr(fdcu_t fdcu)
7535b81b6b3SRodney W. Grimes {
7545b81b6b3SRodney W. Grimes 	fdc_p fdc = fdc_data + fdcu;
755b99f0a4aSAndrew Moore #if NFT > 0
756b99f0a4aSAndrew Moore 	fdu_t fdu = fdc->fdu;
757b99f0a4aSAndrew Moore 
758b99f0a4aSAndrew Moore 	if (fdc->flags & FDC_TAPE_BUSY)
759b99f0a4aSAndrew Moore 		(ftintr(fdu));
760b99f0a4aSAndrew Moore 	else
761b99f0a4aSAndrew Moore #endif
762381fe1aaSGarrett Wollman 	while(fdstate(fdcu, fdc))
763381fe1aaSGarrett Wollman 	  ;
7645b81b6b3SRodney W. Grimes }
7655b81b6b3SRodney W. Grimes 
7665b81b6b3SRodney W. Grimes /***********************************************************************\
7675b81b6b3SRodney W. Grimes * The controller state machine.						*
7685b81b6b3SRodney W. Grimes * if it returns a non zero value, it should be called again immediatly	*
7695b81b6b3SRodney W. Grimes \***********************************************************************/
770381fe1aaSGarrett Wollman int
771381fe1aaSGarrett Wollman fdstate(fdcu, fdc)
772f5f7ba03SJordan K. Hubbard 	fdcu_t fdcu;
773f5f7ba03SJordan K. Hubbard 	fdc_p fdc;
7745b81b6b3SRodney W. Grimes {
775b39c878eSAndrey A. Chernov 	int read, format, head, trac, sec = 0, i = 0, s, sectrac, cyl, st0;
7765b81b6b3SRodney W. Grimes 	unsigned long blknum;
7775b81b6b3SRodney W. Grimes 	fdu_t fdu = fdc->fdu;
7785b81b6b3SRodney W. Grimes 	fd_p fd;
7795b81b6b3SRodney W. Grimes 	register struct buf *dp,*bp;
780b39c878eSAndrey A. Chernov 	struct fd_formb *finfo = NULL;
7815b81b6b3SRodney W. Grimes 
7825b81b6b3SRodney W. Grimes 	dp = &(fdc->head);
7835b81b6b3SRodney W. Grimes 	bp = dp->b_actf;
7845b81b6b3SRodney W. Grimes 	if(!bp)
7855b81b6b3SRodney W. Grimes 	{
7865b81b6b3SRodney W. Grimes 		/***********************************************\
7875b81b6b3SRodney W. Grimes 		* nothing left for this controller to do	*
7885b81b6b3SRodney W. Grimes 		* Force into the IDLE state,			*
7895b81b6b3SRodney W. Grimes 		\***********************************************/
7905b81b6b3SRodney W. Grimes 		fdc->state = DEVIDLE;
7915b81b6b3SRodney W. Grimes 		if(fdc->fd)
7925b81b6b3SRodney W. Grimes 		{
7935b81b6b3SRodney W. Grimes 			printf("unexpected valid fd pointer (fdu = %d)\n"
7945b81b6b3SRodney W. Grimes 						,fdc->fdu);
7955b81b6b3SRodney W. Grimes 			fdc->fd = (fd_p) 0;
7965b81b6b3SRodney W. Grimes 			fdc->fdu = -1;
7975b81b6b3SRodney W. Grimes 		}
7985b81b6b3SRodney W. Grimes 		TRACE1("[fdc%d IDLE]",fdcu);
7995b81b6b3SRodney W. Grimes  		return(0);
8005b81b6b3SRodney W. Grimes 	}
8015b81b6b3SRodney W. Grimes 	fdu = FDUNIT(minor(bp->b_dev));
8025b81b6b3SRodney W. Grimes 	fd = fd_data + fdu;
8035b81b6b3SRodney W. Grimes 	if (fdc->fd && (fd != fdc->fd))
8045b81b6b3SRodney W. Grimes 	{
8055b81b6b3SRodney W. Grimes 		printf("confused fd pointers\n");
8065b81b6b3SRodney W. Grimes 	}
8075b81b6b3SRodney W. Grimes 	read = bp->b_flags & B_READ;
808b39c878eSAndrey A. Chernov 	format = bp->b_flags & B_FORMAT;
809b39c878eSAndrey A. Chernov 	if(format)
810b39c878eSAndrey A. Chernov 		finfo = (struct fd_formb *)bp->b_un.b_addr;
8115b81b6b3SRodney W. Grimes 	TRACE1("fd%d",fdu);
8125b81b6b3SRodney W. Grimes 	TRACE1("[%s]",fdstates[fdc->state]);
8135b81b6b3SRodney W. Grimes 	TRACE1("(0x%x)",fd->flags);
814d0917939SPaul Richards 	untimeout(fd_turnoff, (caddr_t)fdu);
815d0917939SPaul Richards 	timeout(fd_turnoff, (caddr_t)fdu, 4 * hz);
8165b81b6b3SRodney W. Grimes 	switch (fdc->state)
8175b81b6b3SRodney W. Grimes 	{
8185b81b6b3SRodney W. Grimes 	case DEVIDLE:
8195b81b6b3SRodney W. Grimes 	case FINDWORK:	/* we have found new work */
8205b81b6b3SRodney W. Grimes 		fdc->retry = 0;
8215b81b6b3SRodney W. Grimes 		fd->skip = 0;
8225b81b6b3SRodney W. Grimes 		fdc->fd = fd;
8235b81b6b3SRodney W. Grimes 		fdc->fdu = fdu;
824e7e0afeaSNate Williams 		outb(fdc->baseport+fdctl, fd->ft->trans);
8255b81b6b3SRodney W. Grimes 		/*******************************************************\
8265b81b6b3SRodney W. Grimes 		* If the next drive has a motor startup pending, then	*
8275b81b6b3SRodney W. Grimes 		* it will start up in it's own good time		*
8285b81b6b3SRodney W. Grimes 		\*******************************************************/
8295b81b6b3SRodney W. Grimes 		if(fd->flags & FD_MOTOR_WAIT)
8305b81b6b3SRodney W. Grimes 		{
8315b81b6b3SRodney W. Grimes 			fdc->state = MOTORWAIT;
8325b81b6b3SRodney W. Grimes 			return(0); /* come back later */
8335b81b6b3SRodney W. Grimes 		}
8345b81b6b3SRodney W. Grimes 		/*******************************************************\
8355b81b6b3SRodney W. Grimes 		* Maybe if it's not starting, it SHOULD be starting	*
8365b81b6b3SRodney W. Grimes 		\*******************************************************/
8375b81b6b3SRodney W. Grimes 		if (!(fd->flags & FD_MOTOR))
8385b81b6b3SRodney W. Grimes 		{
8395b81b6b3SRodney W. Grimes 			fdc->state = MOTORWAIT;
8405b81b6b3SRodney W. Grimes 			fd_turnon(fdu);
8415b81b6b3SRodney W. Grimes 			return(0);
8425b81b6b3SRodney W. Grimes 		}
8435b81b6b3SRodney W. Grimes 		else	/* at least make sure we are selected */
8445b81b6b3SRodney W. Grimes 		{
8455b81b6b3SRodney W. Grimes 			set_motor(fdcu,fd->fdsu,0);
8465b81b6b3SRodney W. Grimes 		}
8475b81b6b3SRodney W. Grimes 		fdc->state = DOSEEK;
8485b81b6b3SRodney W. Grimes 		break;
8495b81b6b3SRodney W. Grimes 	case DOSEEK:
8505b81b6b3SRodney W. Grimes 		if (bp->b_cylin == fd->track)
8515b81b6b3SRodney W. Grimes 		{
8525b81b6b3SRodney W. Grimes 			fdc->state = SEEKCOMPLETE;
8535b81b6b3SRodney W. Grimes 			break;
8545b81b6b3SRodney W. Grimes 		}
8555b81b6b3SRodney W. Grimes 		out_fdc(fdcu,NE7CMD_SEEK);	/* Seek function */
8565b81b6b3SRodney W. Grimes 		out_fdc(fdcu,fd->fdsu);		/* Drive number */
8575b81b6b3SRodney W. Grimes 		out_fdc(fdcu,bp->b_cylin * fd->ft->steptrac);
8585b81b6b3SRodney W. Grimes 		fd->track = -2;
8595b81b6b3SRodney W. Grimes 		fdc->state = SEEKWAIT;
860d0917939SPaul Richards 		timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
8615b81b6b3SRodney W. Grimes 		return(0);	/* will return later */
8625b81b6b3SRodney W. Grimes 	case SEEKWAIT:
863d0917939SPaul Richards 		untimeout(fd_timeout, (caddr_t)fdcu);
8645b81b6b3SRodney W. Grimes 		/* allow heads to settle */
865d0917939SPaul Richards 		timeout(fd_pseudointr, (caddr_t)fdcu, hz / 50);
8665b81b6b3SRodney W. Grimes 		fdc->state = SEEKCOMPLETE;
8675b81b6b3SRodney W. Grimes 		return(0);	/* will return later */
8685b81b6b3SRodney W. Grimes 		break;
8695b81b6b3SRodney W. Grimes 
8705b81b6b3SRodney W. Grimes 	case SEEKCOMPLETE : /* SEEK DONE, START DMA */
8715b81b6b3SRodney W. Grimes 		/* Make sure seek really happened*/
8725b81b6b3SRodney W. Grimes 		if(fd->track == -2)
8735b81b6b3SRodney W. Grimes 		{
8745b81b6b3SRodney W. Grimes 			int descyl = bp->b_cylin * fd->ft->steptrac;
8755b81b6b3SRodney W. Grimes 			out_fdc(fdcu,NE7CMD_SENSEI);
8765b81b6b3SRodney W. Grimes 			i = in_fdc(fdcu);
8775b81b6b3SRodney W. Grimes 			cyl = in_fdc(fdcu);
8785b81b6b3SRodney W. Grimes 			if (cyl != descyl)
8795b81b6b3SRodney W. Grimes 			{
880b99f0a4aSAndrew Moore 				printf("fd%d: Seek to cyl %d failed; am at cyl %d (ST0 = 0x%x)\n",
881b99f0a4aSAndrew Moore 				fdu, descyl, cyl, i, NE7_ST0BITS);
8825b81b6b3SRodney W. Grimes 				return(retrier(fdcu));
8835b81b6b3SRodney W. Grimes 			}
8845b81b6b3SRodney W. Grimes 		}
8855b81b6b3SRodney W. Grimes 
8865b81b6b3SRodney W. Grimes 		fd->track = bp->b_cylin;
887b39c878eSAndrey A. Chernov 		if(format)
888b39c878eSAndrey A. Chernov 			fd->skip = (char *)&(finfo->fd_formb_cylno(0))
889b39c878eSAndrey A. Chernov 				- (char *)finfo;
8905b81b6b3SRodney W. Grimes 		isa_dmastart(bp->b_flags, bp->b_un.b_addr+fd->skip,
891b39c878eSAndrey A. Chernov 			format ? bp->b_bcount : FDBLK, fdc->dmachan);
8925b81b6b3SRodney W. Grimes 		blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
8935b81b6b3SRodney W. Grimes 			+ fd->skip/FDBLK;
8945b81b6b3SRodney W. Grimes 		sectrac = fd->ft->sectrac;
8955b81b6b3SRodney W. Grimes 		sec = blknum %  (sectrac * fd->ft->heads);
8965b81b6b3SRodney W. Grimes 		head = sec / sectrac;
8975b81b6b3SRodney W. Grimes 		sec = sec % sectrac + 1;
8985b81b6b3SRodney W. Grimes /*XXX*/		fd->hddrv = ((head&1)<<2)+fdu;
8995b81b6b3SRodney W. Grimes 
900b39c878eSAndrey A. Chernov 		if(format)
901b39c878eSAndrey A. Chernov 		{
902b39c878eSAndrey A. Chernov 			/* formatting */
903b39c878eSAndrey A. Chernov 			out_fdc(fdcu,/* NE7CMD_FORMAT */ 0x4d);
904b39c878eSAndrey A. Chernov 			out_fdc(fdcu,head << 2 | fdu);
905b39c878eSAndrey A. Chernov 			out_fdc(fdcu,finfo->fd_formb_secshift);
906b39c878eSAndrey A. Chernov 			out_fdc(fdcu,finfo->fd_formb_nsecs);
907b39c878eSAndrey A. Chernov 			out_fdc(fdcu,finfo->fd_formb_gaplen);
908b39c878eSAndrey A. Chernov 			out_fdc(fdcu,finfo->fd_formb_fillbyte);
909b39c878eSAndrey A. Chernov 		}
910b39c878eSAndrey A. Chernov 		else
911b39c878eSAndrey A. Chernov 		{
9125b81b6b3SRodney W. Grimes 			if (read)
9135b81b6b3SRodney W. Grimes 			{
9145b81b6b3SRodney W. Grimes 				out_fdc(fdcu,NE7CMD_READ);      /* READ */
9155b81b6b3SRodney W. Grimes 			}
9165b81b6b3SRodney W. Grimes 			else
9175b81b6b3SRodney W. Grimes 			{
9185b81b6b3SRodney W. Grimes 				out_fdc(fdcu,NE7CMD_WRITE);     /* WRITE */
9195b81b6b3SRodney W. Grimes 			}
9205b81b6b3SRodney W. Grimes 			out_fdc(fdcu,head << 2 | fdu);  /* head & unit */
9215b81b6b3SRodney W. Grimes 			out_fdc(fdcu,fd->track);        /* track */
9225b81b6b3SRodney W. Grimes 			out_fdc(fdcu,head);
9235b81b6b3SRodney W. Grimes 			out_fdc(fdcu,sec);              /* sector XXX +1? */
9245b81b6b3SRodney W. Grimes 			out_fdc(fdcu,fd->ft->secsize);  /* sector size */
9255b81b6b3SRodney W. Grimes 			out_fdc(fdcu,sectrac);          /* sectors/track */
9265b81b6b3SRodney W. Grimes 			out_fdc(fdcu,fd->ft->gap);      /* gap size */
9275b81b6b3SRodney W. Grimes 			out_fdc(fdcu,fd->ft->datalen);  /* data length */
928b39c878eSAndrey A. Chernov 		}
9295b81b6b3SRodney W. Grimes 		fdc->state = IOCOMPLETE;
930d0917939SPaul Richards 		timeout(fd_timeout, (caddr_t)fdcu, 2 * hz);
9315b81b6b3SRodney W. Grimes 		return(0);	/* will return later */
9325b81b6b3SRodney W. Grimes 	case IOCOMPLETE: /* IO DONE, post-analyze */
933d0917939SPaul Richards 		untimeout(fd_timeout, (caddr_t)fdcu);
9345b81b6b3SRodney W. Grimes 		for(i=0;i<7;i++)
9355b81b6b3SRodney W. Grimes 		{
9365b81b6b3SRodney W. Grimes 			fdc->status[i] = in_fdc(fdcu);
9375b81b6b3SRodney W. Grimes 		}
9385b81b6b3SRodney W. Grimes 	case IOTIMEDOUT: /*XXX*/
9395b81b6b3SRodney W. Grimes 		isa_dmadone(bp->b_flags, bp->b_un.b_addr+fd->skip,
940b39c878eSAndrey A. Chernov 			format ? bp->b_bcount : FDBLK, fdc->dmachan);
9415b81b6b3SRodney W. Grimes 		if (fdc->status[0]&0xF8)
9425b81b6b3SRodney W. Grimes 		{
943b39c878eSAndrey A. Chernov                         if (fdc->status[1] & 0x10) {
944b39c878eSAndrey A. Chernov                                 /*
945b39c878eSAndrey A. Chernov 				 * Operation not completed in reasonable time.
946b39c878eSAndrey A. Chernov 				 * Just restart it, don't increment retry count.
947b39c878eSAndrey A. Chernov 				 * (vak)
948b39c878eSAndrey A. Chernov                                  */
949b39c878eSAndrey A. Chernov                                 fdc->state = SEEKCOMPLETE;
950b39c878eSAndrey A. Chernov                                 return (1);
951b39c878eSAndrey A. Chernov                         }
9525b81b6b3SRodney W. Grimes 			return(retrier(fdcu));
9535b81b6b3SRodney W. Grimes 		}
9545b81b6b3SRodney W. Grimes 		/* All OK */
9555b81b6b3SRodney W. Grimes 		fd->skip += FDBLK;
956b39c878eSAndrey A. Chernov 		if (!format && fd->skip < bp->b_bcount)
9575b81b6b3SRodney W. Grimes 		{
9585b81b6b3SRodney W. Grimes 			/* set up next transfer */
9595b81b6b3SRodney W. Grimes 			blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
9605b81b6b3SRodney W. Grimes 				+ fd->skip/FDBLK;
9615b81b6b3SRodney W. Grimes 			bp->b_cylin = (blknum / (fd->ft->sectrac * fd->ft->heads));
9625b81b6b3SRodney W. Grimes 			fdc->state = DOSEEK;
9635b81b6b3SRodney W. Grimes 		}
9645b81b6b3SRodney W. Grimes 		else
9655b81b6b3SRodney W. Grimes 		{
9665b81b6b3SRodney W. Grimes 			/* ALL DONE */
9675b81b6b3SRodney W. Grimes 			fd->skip = 0;
9685b81b6b3SRodney W. Grimes 			bp->b_resid = 0;
96926f9a767SRodney W. Grimes 			dp->b_actf = bp->b_actf;
9705b81b6b3SRodney W. Grimes 			biodone(bp);
9715b81b6b3SRodney W. Grimes 			fdc->fd = (fd_p) 0;
9725b81b6b3SRodney W. Grimes 			fdc->fdu = -1;
9735b81b6b3SRodney W. Grimes 			fdc->state = FINDWORK;
9745b81b6b3SRodney W. Grimes 		}
9755b81b6b3SRodney W. Grimes 		return(1);
9765b81b6b3SRodney W. Grimes 	case RESETCTLR:
9775b81b6b3SRodney W. Grimes 		/* Try a reset, keep motor on */
9785b81b6b3SRodney W. Grimes 		set_motor(fdcu,fd->fdsu,1);
9795b81b6b3SRodney W. Grimes 		DELAY(100);
9805b81b6b3SRodney W. Grimes 		set_motor(fdcu,fd->fdsu,0);
9815b81b6b3SRodney W. Grimes 		outb(fdc->baseport+fdctl,fd->ft->trans);
9825b81b6b3SRodney W. Grimes 		TRACE1("[0x%x->fdctl]",fd->ft->trans);
9835b81b6b3SRodney W. Grimes 		fdc->retry++;
9845b81b6b3SRodney W. Grimes 		fdc->state = STARTRECAL;
9855b81b6b3SRodney W. Grimes 		break;
9865b81b6b3SRodney W. Grimes 	case STARTRECAL:
9875b81b6b3SRodney W. Grimes 		out_fdc(fdcu,NE7CMD_SPECIFY); /* specify command */
9885b81b6b3SRodney W. Grimes 		out_fdc(fdcu,0xDF);
9895b81b6b3SRodney W. Grimes 		out_fdc(fdcu,2);
9905b81b6b3SRodney W. Grimes 		out_fdc(fdcu,NE7CMD_RECAL);	/* Recalibrate Function */
9915b81b6b3SRodney W. Grimes 		out_fdc(fdcu,fdu);
9925b81b6b3SRodney W. Grimes 		fdc->state = RECALWAIT;
9935b81b6b3SRodney W. Grimes 		return(0);	/* will return later */
9945b81b6b3SRodney W. Grimes 	case RECALWAIT:
9955b81b6b3SRodney W. Grimes 		/* allow heads to settle */
996d0917939SPaul Richards 		timeout(fd_pseudointr, (caddr_t)fdcu, hz / 30);
9975b81b6b3SRodney W. Grimes 		fdc->state = RECALCOMPLETE;
9985b81b6b3SRodney W. Grimes 		return(0);	/* will return later */
9995b81b6b3SRodney W. Grimes 	case RECALCOMPLETE:
10005b81b6b3SRodney W. Grimes 		out_fdc(fdcu,NE7CMD_SENSEI);
10015b81b6b3SRodney W. Grimes 		st0 = in_fdc(fdcu);
10025b81b6b3SRodney W. Grimes 		cyl = in_fdc(fdcu);
10035b81b6b3SRodney W. Grimes 		if (cyl != 0)
10045b81b6b3SRodney W. Grimes 		{
10055b81b6b3SRodney W. Grimes 			printf("fd%d: recal failed ST0 %b cyl %d\n", fdu,
10065b81b6b3SRodney W. Grimes 				st0, NE7_ST0BITS, cyl);
10075b81b6b3SRodney W. Grimes 			return(retrier(fdcu));
10085b81b6b3SRodney W. Grimes 		}
10095b81b6b3SRodney W. Grimes 		fd->track = 0;
10105b81b6b3SRodney W. Grimes 		/* Seek (probably) necessary */
10115b81b6b3SRodney W. Grimes 		fdc->state = DOSEEK;
10125b81b6b3SRodney W. Grimes 		return(1);	/* will return immediatly */
10135b81b6b3SRodney W. Grimes 	case	MOTORWAIT:
10145b81b6b3SRodney W. Grimes 		if(fd->flags & FD_MOTOR_WAIT)
10155b81b6b3SRodney W. Grimes 		{
10165b81b6b3SRodney W. Grimes 			return(0); /* time's not up yet */
10175b81b6b3SRodney W. Grimes 		}
10185b81b6b3SRodney W. Grimes 		fdc->state = DOSEEK;
10195b81b6b3SRodney W. Grimes 		return(1);	/* will return immediatly */
10205b81b6b3SRodney W. Grimes 	default:
10215b81b6b3SRodney W. Grimes 		printf("Unexpected FD int->");
10225b81b6b3SRodney W. Grimes 		out_fdc(fdcu,NE7CMD_SENSEI);
10235b81b6b3SRodney W. Grimes 		st0 = in_fdc(fdcu);
10245b81b6b3SRodney W. Grimes 		cyl = in_fdc(fdcu);
10255b81b6b3SRodney W. Grimes 		printf("ST0 = %lx, PCN = %lx\n",i,sec);
10265b81b6b3SRodney W. Grimes 		out_fdc(fdcu,0x4A);
10275b81b6b3SRodney W. Grimes 		out_fdc(fdcu,fd->fdsu);
10285b81b6b3SRodney W. Grimes 		for(i=0;i<7;i++) {
10295b81b6b3SRodney W. Grimes 			fdc->status[i] = in_fdc(fdcu);
10305b81b6b3SRodney W. Grimes 		}
10315b81b6b3SRodney W. Grimes 	printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
10325b81b6b3SRodney W. Grimes 		fdc->status[0],
10335b81b6b3SRodney W. Grimes 		fdc->status[1],
10345b81b6b3SRodney W. Grimes 		fdc->status[2],
10355b81b6b3SRodney W. Grimes 		fdc->status[3],
10365b81b6b3SRodney W. Grimes 		fdc->status[4],
10375b81b6b3SRodney W. Grimes 		fdc->status[5],
10385b81b6b3SRodney W. Grimes 		fdc->status[6] );
10395b81b6b3SRodney W. Grimes 		return(0);
10405b81b6b3SRodney W. Grimes 	}
10415b81b6b3SRodney W. Grimes 	return(1); /* Come back immediatly to new state */
10425b81b6b3SRodney W. Grimes }
10435b81b6b3SRodney W. Grimes 
1044aaf08d94SGarrett Wollman static int
1045f5f7ba03SJordan K. Hubbard retrier(fdcu)
1046f5f7ba03SJordan K. Hubbard 	fdcu_t fdcu;
10475b81b6b3SRodney W. Grimes {
10485b81b6b3SRodney W. Grimes 	fdc_p fdc = fdc_data + fdcu;
10495b81b6b3SRodney W. Grimes 	register struct buf *dp,*bp;
10505b81b6b3SRodney W. Grimes 
10515b81b6b3SRodney W. Grimes 	dp = &(fdc->head);
10525b81b6b3SRodney W. Grimes 	bp = dp->b_actf;
10535b81b6b3SRodney W. Grimes 
10545b81b6b3SRodney W. Grimes 	switch(fdc->retry)
10555b81b6b3SRodney W. Grimes 	{
10565b81b6b3SRodney W. Grimes 	case 0: case 1: case 2:
10575b81b6b3SRodney W. Grimes 		fdc->state = SEEKCOMPLETE;
10585b81b6b3SRodney W. Grimes 		break;
10595b81b6b3SRodney W. Grimes 	case 3: case 4: case 5:
10605b81b6b3SRodney W. Grimes 		fdc->state = STARTRECAL;
10615b81b6b3SRodney W. Grimes 		break;
10625b81b6b3SRodney W. Grimes 	case 6:
10635b81b6b3SRodney W. Grimes 		fdc->state = RESETCTLR;
10645b81b6b3SRodney W. Grimes 		break;
10655b81b6b3SRodney W. Grimes 	case 7:
10665b81b6b3SRodney W. Grimes 		break;
10675b81b6b3SRodney W. Grimes 	default:
10685b81b6b3SRodney W. Grimes 		{
10697ca0641bSAndrey A. Chernov 			dev_t sav_b_dev = bp->b_dev;
10707ca0641bSAndrey A. Chernov 			/* Trick diskerr */
1071b2be795bSAndrey A. Chernov 			bp->b_dev = makedev(major(bp->b_dev), (FDUNIT(minor(bp->b_dev))<<3)|RAW_PART);
107292ed385aSRodney W. Grimes 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
107392ed385aSRodney W. Grimes 				fdc->fd->skip, (struct disklabel *)NULL);
10747ca0641bSAndrey A. Chernov 			bp->b_dev = sav_b_dev;
107592ed385aSRodney W. Grimes 			printf(" (ST0 %b ", fdc->status[0], NE7_ST0BITS);
10765b81b6b3SRodney W. Grimes 			printf(" ST1 %b ", fdc->status[1], NE7_ST1BITS);
10775b81b6b3SRodney W. Grimes 			printf(" ST2 %b ", fdc->status[2], NE7_ST2BITS);
10785b81b6b3SRodney W. Grimes 			printf("cyl %d hd %d sec %d)\n",
107992ed385aSRodney W. Grimes 			       fdc->status[3], fdc->status[4], fdc->status[5]);
10805b81b6b3SRodney W. Grimes 		}
10815b81b6b3SRodney W. Grimes 		bp->b_flags |= B_ERROR;
10825b81b6b3SRodney W. Grimes 		bp->b_error = EIO;
10835b81b6b3SRodney W. Grimes 		bp->b_resid = bp->b_bcount - fdc->fd->skip;
108426f9a767SRodney W. Grimes 		dp->b_actf = bp->b_actf;
10855b81b6b3SRodney W. Grimes 		fdc->fd->skip = 0;
10865b81b6b3SRodney W. Grimes 		biodone(bp);
108792ed385aSRodney W. Grimes 		fdc->state = FINDWORK;
10885b81b6b3SRodney W. Grimes 		fdc->fd = (fd_p) 0;
10895b81b6b3SRodney W. Grimes 		fdc->fdu = -1;
1090f5f7ba03SJordan K. Hubbard 		/* XXX abort current command, if any.  */
109192ed385aSRodney W. Grimes 		return(1);
10925b81b6b3SRodney W. Grimes 	}
10935b81b6b3SRodney W. Grimes 	fdc->retry++;
10945b81b6b3SRodney W. Grimes 	return(1);
10955b81b6b3SRodney W. Grimes }
10965b81b6b3SRodney W. Grimes 
1097b39c878eSAndrey A. Chernov static int
1098b39c878eSAndrey A. Chernov fdformat(dev, finfo, p)
1099b39c878eSAndrey A. Chernov 	dev_t dev;
1100b39c878eSAndrey A. Chernov 	struct fd_formb *finfo;
1101b39c878eSAndrey A. Chernov 	struct proc *p;
1102b39c878eSAndrey A. Chernov {
1103b39c878eSAndrey A. Chernov  	fdu_t	fdu;
1104b39c878eSAndrey A. Chernov  	fd_p	fd;
1105b39c878eSAndrey A. Chernov 
1106b39c878eSAndrey A. Chernov 	struct buf *bp;
1107b39c878eSAndrey A. Chernov 	int rv = 0, s;
1108b39c878eSAndrey A. Chernov 
1109b39c878eSAndrey A. Chernov  	fdu = FDUNIT(minor(dev));
1110b39c878eSAndrey A. Chernov 	fd = &fd_data[fdu];
1111b39c878eSAndrey A. Chernov 
1112b39c878eSAndrey A. Chernov 	/* set up a buffer header for fdstrategy() */
1113b39c878eSAndrey A. Chernov 	bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1114b39c878eSAndrey A. Chernov 	if(bp == 0)
1115b39c878eSAndrey A. Chernov 		return ENOBUFS;
1116b39c878eSAndrey A. Chernov 	bzero((void *)bp, sizeof(struct buf));
1117b39c878eSAndrey A. Chernov 	bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1118b39c878eSAndrey A. Chernov 	bp->b_proc = p;
1119b39c878eSAndrey A. Chernov 	bp->b_dev = dev;
1120b39c878eSAndrey A. Chernov 
1121b39c878eSAndrey A. Chernov 	/*
1122b39c878eSAndrey A. Chernov 	 * calculate a fake blkno, so fdstrategy() would initiate a
1123b39c878eSAndrey A. Chernov 	 * seek to the requested cylinder
1124b39c878eSAndrey A. Chernov 	 */
1125b39c878eSAndrey A. Chernov 	bp->b_blkno = (finfo->cyl * (fd->ft->sectrac * fd->ft->heads)
1126b39c878eSAndrey A. Chernov 		+ finfo->head * fd->ft->sectrac) * FDBLK / DEV_BSIZE;
1127b39c878eSAndrey A. Chernov 
1128b39c878eSAndrey A. Chernov 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1129b39c878eSAndrey A. Chernov 	bp->b_un.b_addr = (caddr_t)finfo;
1130b39c878eSAndrey A. Chernov 
1131b39c878eSAndrey A. Chernov 	/* now do the format */
1132b39c878eSAndrey A. Chernov 	fdstrategy(bp);
1133b39c878eSAndrey A. Chernov 
1134b39c878eSAndrey A. Chernov 	/* ...and wait for it to complete */
1135b39c878eSAndrey A. Chernov 	s = splbio();
1136b39c878eSAndrey A. Chernov 	while(!(bp->b_flags & B_DONE))
1137b39c878eSAndrey A. Chernov 	{
1138b39c878eSAndrey A. Chernov 		rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1139b39c878eSAndrey A. Chernov 		if(rv == EWOULDBLOCK)
1140b39c878eSAndrey A. Chernov 			break;
1141b39c878eSAndrey A. Chernov 	}
1142b39c878eSAndrey A. Chernov 	splx(s);
1143b39c878eSAndrey A. Chernov 
1144b39c878eSAndrey A. Chernov 	if(rv == EWOULDBLOCK)
1145b39c878eSAndrey A. Chernov 	{
1146b39c878eSAndrey A. Chernov 		/* timed out */
1147b39c878eSAndrey A. Chernov 		biodone(bp);
1148b39c878eSAndrey A. Chernov 		rv = EIO;
1149b39c878eSAndrey A. Chernov 	}
1150b39c878eSAndrey A. Chernov 	free(bp, M_TEMP);
1151b39c878eSAndrey A. Chernov 	return rv;
1152b39c878eSAndrey A. Chernov }
1153b39c878eSAndrey A. Chernov 
1154f5f7ba03SJordan K. Hubbard /*
1155f5f7ba03SJordan K. Hubbard  * fdioctl() from jc@irbs.UUCP (John Capo)
1156f5f7ba03SJordan K. Hubbard  * i386/i386/conf.c needs to have fdioctl() declared and remove the line that
1157f5f7ba03SJordan K. Hubbard  * defines fdioctl to be enxio.
1158f5f7ba03SJordan K. Hubbard  *
1159f5f7ba03SJordan K. Hubbard  * TODO: Reformat.
1160f5f7ba03SJordan K. Hubbard  *       Think about allocating buffer off stack.
1161f5f7ba03SJordan K. Hubbard  *       Don't pass uncast 0's and NULL's to read/write/setdisklabel().
1162f5f7ba03SJordan K. Hubbard  *       Watch out for NetBSD's different *disklabel() interface.
1163b39c878eSAndrey A. Chernov  *
1164b39c878eSAndrey A. Chernov  * Added functionality for floppy formatting
1165b39c878eSAndrey A. Chernov  * joerg_wunsch@uriah.sax.de (Joerg Wunsch)
1166f5f7ba03SJordan K. Hubbard  */
11675b81b6b3SRodney W. Grimes 
1168f5f7ba03SJordan K. Hubbard int
1169b39c878eSAndrey A. Chernov fdioctl (dev, cmd, addr, flag, p)
1170f5f7ba03SJordan K. Hubbard 	dev_t dev;
1171f5f7ba03SJordan K. Hubbard 	int cmd;
1172f5f7ba03SJordan K. Hubbard 	caddr_t addr;
1173f5f7ba03SJordan K. Hubbard 	int flag;
1174b39c878eSAndrey A. Chernov 	struct proc *p;
1175f5f7ba03SJordan K. Hubbard {
1176f5f7ba03SJordan K. Hubbard 	struct fd_type *fdt;
1177f5f7ba03SJordan K. Hubbard 	struct disklabel *dl;
1178f5f7ba03SJordan K. Hubbard 	char buffer[DEV_BSIZE];
1179f5f7ba03SJordan K. Hubbard 	int error;
1180f5f7ba03SJordan K. Hubbard 
1181b99f0a4aSAndrew Moore #if NFT > 0
1182a60eff27SNate Williams 	int type = FDTYPE(minor(dev));
1183a60eff27SNate Williams 
1184a60eff27SNate Williams 	/* check for a tape ioctl */
1185a60eff27SNate Williams 	if (type & F_TAPE_TYPE)
1186b99f0a4aSAndrew Moore 		return ftioctl(dev, cmd, addr, flag, p);
1187b99f0a4aSAndrew Moore #endif
1188b99f0a4aSAndrew Moore 
1189f5f7ba03SJordan K. Hubbard 	error = 0;
1190f5f7ba03SJordan K. Hubbard 
1191f5f7ba03SJordan K. Hubbard 	switch (cmd)
1192f5f7ba03SJordan K. Hubbard 	{
1193f5f7ba03SJordan K. Hubbard 	case DIOCGDINFO:
1194f5f7ba03SJordan K. Hubbard 		bzero(buffer, sizeof (buffer));
1195f5f7ba03SJordan K. Hubbard 		dl = (struct disklabel *)buffer;
1196f5f7ba03SJordan K. Hubbard 		dl->d_secsize = FDBLK;
119792ed385aSRodney W. Grimes 		fdt = fd_data[FDUNIT(minor(dev))].ft;
1198f5f7ba03SJordan K. Hubbard 		dl->d_secpercyl = fdt->size / fdt->tracks;
1199f5f7ba03SJordan K. Hubbard 		dl->d_type = DTYPE_FLOPPY;
1200f5f7ba03SJordan K. Hubbard 
1201f5f7ba03SJordan K. Hubbard 		if (readdisklabel(dev, fdstrategy, dl, NULL, 0, 0) == NULL)
1202f5f7ba03SJordan K. Hubbard 			error = 0;
1203f5f7ba03SJordan K. Hubbard 		else
1204f5f7ba03SJordan K. Hubbard 			error = EINVAL;
1205f5f7ba03SJordan K. Hubbard 
1206f5f7ba03SJordan K. Hubbard 		*(struct disklabel *)addr = *dl;
1207f5f7ba03SJordan K. Hubbard 		break;
1208f5f7ba03SJordan K. Hubbard 
1209f5f7ba03SJordan K. Hubbard 	case DIOCSDINFO:
1210f5f7ba03SJordan K. Hubbard 		if ((flag & FWRITE) == 0)
1211f5f7ba03SJordan K. Hubbard 			error = EBADF;
1212f5f7ba03SJordan K. Hubbard 		break;
1213f5f7ba03SJordan K. Hubbard 
1214f5f7ba03SJordan K. Hubbard 	case DIOCWLABEL:
1215f5f7ba03SJordan K. Hubbard 		if ((flag & FWRITE) == 0)
1216f5f7ba03SJordan K. Hubbard 			error = EBADF;
1217f5f7ba03SJordan K. Hubbard 		break;
1218f5f7ba03SJordan K. Hubbard 
1219f5f7ba03SJordan K. Hubbard 	case DIOCWDINFO:
1220f5f7ba03SJordan K. Hubbard 		if ((flag & FWRITE) == 0)
1221f5f7ba03SJordan K. Hubbard 		{
1222f5f7ba03SJordan K. Hubbard 			error = EBADF;
1223f5f7ba03SJordan K. Hubbard 			break;
1224f5f7ba03SJordan K. Hubbard 		}
1225f5f7ba03SJordan K. Hubbard 
1226f5f7ba03SJordan K. Hubbard 		dl = (struct disklabel *)addr;
1227f5f7ba03SJordan K. Hubbard 
1228b39c878eSAndrey A. Chernov 		if (error = setdisklabel ((struct disklabel *)buffer,
1229b39c878eSAndrey A. Chernov 		    dl, 0, NULL))
1230f5f7ba03SJordan K. Hubbard 			break;
1231f5f7ba03SJordan K. Hubbard 
1232b39c878eSAndrey A. Chernov 		error = writedisklabel(dev, fdstrategy,
1233b39c878eSAndrey A. Chernov 			(struct disklabel *)buffer, NULL);
1234b39c878eSAndrey A. Chernov 		break;
1235b39c878eSAndrey A. Chernov 
1236b39c878eSAndrey A. Chernov 	case FD_FORM:
1237b39c878eSAndrey A. Chernov 		if((flag & FWRITE) == 0)
1238b39c878eSAndrey A. Chernov 			error = EBADF;	/* must be opened for writing */
1239b39c878eSAndrey A. Chernov 		else if(((struct fd_formb *)addr)->format_version !=
1240b39c878eSAndrey A. Chernov 			FD_FORMAT_VERSION)
1241b39c878eSAndrey A. Chernov 			error = EINVAL;	/* wrong version of formatting prog */
1242b39c878eSAndrey A. Chernov 		else
1243b39c878eSAndrey A. Chernov 			error = fdformat(dev, (struct fd_formb *)addr, p);
1244b39c878eSAndrey A. Chernov 		break;
1245b39c878eSAndrey A. Chernov 
1246b39c878eSAndrey A. Chernov 	case FD_GTYPE:                  /* get drive type */
1247b39c878eSAndrey A. Chernov 		*(struct fd_type *)addr = *fd_data[FDUNIT(minor(dev))].ft;
1248f5f7ba03SJordan K. Hubbard 		break;
1249f5f7ba03SJordan K. Hubbard 
1250f5f7ba03SJordan K. Hubbard 	default:
1251f5f7ba03SJordan K. Hubbard 		error = EINVAL;
1252f5f7ba03SJordan K. Hubbard 		break;
1253f5f7ba03SJordan K. Hubbard 	}
1254f5f7ba03SJordan K. Hubbard 	return (error);
1255f5f7ba03SJordan K. Hubbard }
1256f5f7ba03SJordan K. Hubbard 
1257f5f7ba03SJordan K. Hubbard #endif
1258