xref: /netbsd-src/sys/arch/sun3/dev/fd.c (revision 4b896b232495b7a9b8b94a1cf1e21873296d53b8)
1 /*	$NetBSD: fd.c,v 1.40 2004/03/24 15:44:46 pk Exp $	*/
2 
3 /*-
4  * Copyright (c) 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Don Ahn.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
35  */
36 
37 /*-
38  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.
39  *
40  * This code is derived from software contributed to Berkeley by
41  * Don Ahn.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  * 3. All advertising materials mentioning features or use of this software
52  *    must display the following acknowledgement:
53  *	This product includes software developed by the University of
54  *	California, Berkeley and its contributors.
55  * 4. Neither the name of the University nor the names of its contributors
56  *    may be used to endorse or promote products derived from this software
57  *    without specific prior written permission.
58  *
59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69  * SUCH DAMAGE.
70  *
71  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
72  */
73 
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.40 2004/03/24 15:44:46 pk Exp $");
76 
77 #include "opt_ddb.h"
78 
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/callout.h>
82 #include <sys/kernel.h>
83 #include <sys/file.h>
84 #include <sys/ioctl.h>
85 #include <sys/device.h>
86 #include <sys/disklabel.h>
87 #include <sys/disk.h>
88 #include <sys/fdio.h>
89 #include <sys/buf.h>
90 #include <sys/malloc.h>
91 #include <sys/proc.h>
92 #include <sys/uio.h>
93 #include <sys/stat.h>
94 #include <sys/syslog.h>
95 #include <sys/queue.h>
96 #include <sys/conf.h>
97 
98 #include <dev/cons.h>
99 
100 #include <uvm/uvm_extern.h>
101 
102 #include <machine/cpu.h>
103 #include <machine/autoconf.h>
104 
105 #include <sun3/dev/fdreg.h>
106 #include <sun3/dev/fdvar.h>
107 
108 /*
109  * Print a complaint when no fd children were specified
110  * in the config file.  Better than a link error...
111  *
112  * XXX: Some folks say this driver should be split in two,
113  * but that seems pointless with ONLY one type of child.
114  * (Thankfully, no 3/80 boxes have floppy tapes!:)
115  */
116 #include "fdc.h"
117 #if NFD == 0
118 #error "fdc but no fd?"
119 #endif
120 
121 #define FDUNIT(dev)	(minor(dev) / 8)
122 #define FDTYPE(dev)	(minor(dev) % 8)
123 
124 /* XXX misuse a flag to identify format operation */
125 #define B_FORMAT B_XXX
126 
127 #ifdef FD_DEBUG
128 int	fdc_debug = 0;
129 #endif
130 
131 enum fdc_state {
132 	DEVIDLE = 0,
133 	MOTORWAIT,
134 	DOSEEK,
135 	SEEKWAIT,
136 	SEEKTIMEDOUT,
137 	SEEKCOMPLETE,
138 	DOIO,
139 	IOCOMPLETE,
140 	IOTIMEDOUT,
141 	DORESET,
142 	RESETCOMPLETE,
143 	RESETTIMEDOUT,
144 	DORECAL,
145 	RECALWAIT,
146 	RECALTIMEDOUT,
147 	RECALCOMPLETE,
148 };
149 
150 /* software state, per controller */
151 struct fdc_softc {
152 	struct device	sc_dev;		/* boilerplate */
153 	caddr_t		sc_reg;
154 
155 	struct callout sc_timo_ch;	/* timeout callout */
156 	struct callout sc_intr_ch;	/* pseudo-intr callout */
157 
158 	struct fd_softc *sc_fd[4];	/* pointers to children */
159 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
160 	enum fdc_state	sc_state;
161 	int		sc_flags;
162 #define FDC_82077		0x01
163 #define FDC_NEEDHEADSETTLE	0x02
164 #define FDC_EIS			0x04
165 	int		sc_errors;		/* number of retries so far */
166 	int		sc_overruns;		/* number of DMA overruns */
167 	int		sc_cfg;			/* current configuration */
168 	int		sc_fcr;			/* current image of floppy ctrlr reg. */
169 	struct fdcio	sc_io;
170 #define sc_reg_msr	sc_io.fdcio_reg_msr
171 #define sc_reg_fifo	sc_io.fdcio_reg_fifo
172 #define sc_reg_fcr	sc_io.fdcio_reg_fcr
173 #define	sc_reg_fvr	sc_io.fdcio_reg_fvr
174 #define sc_reg_drs	sc_io.fdcio_reg_msr
175 #define sc_istate	sc_io.fdcio_istate
176 #define sc_data		sc_io.fdcio_data
177 #define sc_tc		sc_io.fdcio_tc
178 #define sc_nstat	sc_io.fdcio_nstat
179 #define sc_status	sc_io.fdcio_status
180 #define sc_intrcnt	sc_io.fdcio_intrcnt
181 };
182 
183 /* controller driver configuration */
184 int	fdcmatch __P((struct device *, struct cfdata *, void *));
185 void	fdcattach __P((struct device *, struct device *, void *));
186 
187 CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
188     fdcmatch, fdcattach, NULL, NULL);
189 
190 extern struct cfdriver fdc_cd;
191 
192 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
193 
194 /*
195  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
196  * we tell them apart.
197  */
198 struct fd_type {
199 	int	sectrac;	/* sectors per track */
200 	int	heads;		/* number of heads */
201 	int	seccyl;		/* sectors per cylinder */
202 	int	secsize;	/* size code for sectors */
203 	int	datalen;	/* data len when secsize = 0 */
204 	int	steprate;	/* step rate and head unload time */
205 	int	gap1;		/* gap len between sectors */
206 	int	gap2;		/* formatting gap */
207 	int	tracks;		/* total num of tracks */
208 	int	size;		/* size of disk in sectors */
209 	int	step;		/* steps per cylinder */
210 	int	rate;		/* transfer speed code */
211 	int	fillbyte;	/* format fill byte */
212 	int	interleave;	/* interleave factor (formatting) */
213 	char	*name;
214 };
215 
216 /* The order of entries in the following table is important -- BEWARE! */
217 struct fd_type fd_types[] = {
218 	{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB"    }, /* 1.44MB diskette */
219 	{ 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB"    }, /* 1.2 MB AT-diskettes */
220 	{  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
221 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
222 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB"    }, /* 3.5" 720kB diskette */
223 	{  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x"  }, /* 720kB in 1.2MB drive */
224 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x"  }, /* 360kB in 720kB drive */
225 };
226 
227 /* software state, per disk (with up to 4 disks per ctlr) */
228 struct fd_softc {
229 	struct device	sc_dv;		/* generic device info */
230 	struct disk	sc_dk;		/* generic disk info */
231 
232 	struct fd_type *sc_deftype;	/* default type descriptor */
233 	struct fd_type *sc_type;	/* current type descriptor */
234 
235 	struct callout sc_motoron_ch;
236 	struct callout sc_motoroff_ch;
237 
238 	daddr_t	sc_blkno;	/* starting block number */
239 	int sc_bcount;		/* byte count left */
240 	int sc_skip;		/* bytes already transferred */
241 	int sc_nblks;		/* number of blocks currently transferring */
242 	int sc_nbytes;		/* number of bytes currently transferring */
243 
244 	int sc_drive;		/* physical unit number */
245 	int sc_flags;
246 #define	FD_OPEN		0x01		/* it's open */
247 #define	FD_MOTOR	0x02		/* motor should be on */
248 #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
249 	int sc_cylin;		/* where we think the head is */
250 	int sc_opts;		/* user-set options */
251 
252 	void	*sc_sdhook;	/* shutdownhook cookie */
253 
254 	TAILQ_ENTRY(fd_softc) sc_drivechain;
255 	int sc_ops;		/* I/O ops since last switch */
256 	struct bufq_state sc_q;	/* pending I/O requests */
257 	int sc_active;		/* number of active I/O operations */
258 };
259 
260 /* floppy driver configuration */
261 int	fdmatch __P((struct device *, struct cfdata *, void *));
262 void	fdattach __P((struct device *, struct device *, void *));
263 
264 CFATTACH_DECL(fd, sizeof(struct fd_softc),
265     fdmatch, fdattach, NULL, NULL);
266 
267 extern struct cfdriver fd_cd;
268 
269 dev_type_open(fdopen);
270 dev_type_close(fdclose);
271 dev_type_read(fdread);
272 dev_type_write(fdwrite);
273 dev_type_ioctl(fdioctl);
274 dev_type_strategy(fdstrategy);
275 
276 const struct bdevsw fd_bdevsw = {
277 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
278 };
279 
280 const struct cdevsw fd_cdevsw = {
281 	fdopen, fdclose, fdread, fdwrite, fdioctl,
282 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
283 };
284 
285 void fdgetdisklabel __P((dev_t));
286 int fd_get_parms __P((struct fd_softc *));
287 void fdstart __P((struct fd_softc *));
288 int fdprint __P((void *, const char *));
289 
290 struct dkdriver fddkdriver = { fdstrategy };
291 
292 struct	fd_type *fd_nvtotype __P((char *, int, int));
293 void	fd_set_motor __P((struct fdc_softc *fdc));
294 void	fd_motor_off __P((void *arg));
295 void	fd_motor_on __P((void *arg));
296 int	fdcresult __P((struct fdc_softc *fdc));
297 int	out_fdc __P((struct fdc_softc *fdc, u_char x));
298 void	fdcstart __P((struct fdc_softc *fdc));
299 void	fdcstatus __P((struct device *dv, int n, char *s));
300 void	fdc_reset __P((struct fdc_softc *fdc));
301 void	fdctimeout __P((void *arg));
302 void	fdcpseudointr __P((void *arg));
303 int	fdchwintr __P((void *));
304 int	fdcswintr __P((void *));
305 int	fdcstate __P((struct fdc_softc *));
306 void	fdcretry __P((struct fdc_softc *fdc));
307 void	fdfinish __P((struct fd_softc *fd, struct buf *bp));
308 int	fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
309 void	fd_do_eject __P((struct fdc_softc *, int));
310 void	fd_mountroot_hook __P((struct device *));
311 static void fdconf __P((struct fdc_softc *));
312 
313 static int fdc_softpend = 0;
314 #ifndef	FDC_SOFTPRI
315 #define	FDC_SOFTPRI	2
316 #endif
317 #define FD_SET_SWINTR()	{ fdc_softpend = 1; isr_soft_request(FDC_SOFTPRI); }
318 
319 /*
320  * The Floppy Control Register on the sun3x, not to be confused with the
321  * Floppy ControllER Registers that this driver mostly insterfaces with,
322  * controls some of the auxillary functions of the floppy drive.  These
323  * include asserting the floppy eject and terminal data count (or TC) pins
324  * of the floppy drive and controller chip respectively.
325  *
326  * Often it is necessary to toggle individual bits within this register
327  * while keeping the others untouched.  However, the register does not
328  * present its latched data to the processor when read.  This prevents the
329  * use of a read-modify-write cycle that would normally be used to modify
330  * individual bits.  To get around this we must keep a copy of register's
331  * current value and always insure that when we wish to modify the register,
332  * we actually modify the copy and synchronize the register to it.
333  */
334 #define	FCR_REG_SYNC()	(*fdc->sc_reg_fcr = fdc->sc_fcr)
335 
336 int
337 fdcmatch(parent, match, aux)
338 	struct device *parent;
339 	struct cfdata *match;
340 	void *aux;
341 {
342 	struct confargs *ca = aux;
343 
344 	if (bus_peek(ca->ca_bustype, ca->ca_paddr, sizeof(u_char)) == -1)
345 		return (0);
346 
347 	return (1);
348 }
349 
350 /*
351  * Arguments passed between fdcattach and fdprobe.
352  */
353 struct fdc_attach_args {
354 	int fa_drive;
355 	struct bootpath *fa_bootpath;
356 	struct fd_type *fa_deftype;
357 };
358 
359 /*
360  * Print the location of a disk drive (called just before attaching the
361  * the drive).  If `fdc' is not NULL, the drive was found but was not
362  * in the system config file; print the drive name as well.
363  * Return QUIET (config_find ignores this if the device was configured) to
364  * avoid printing `fdN not configured' messages.
365  */
366 int
367 fdprint(aux, fdc)
368 	void *aux;
369 	const char *fdc;
370 {
371 	struct fdc_attach_args *fa = aux;
372 
373 	if (!fdc)
374 		aprint_normal(" drive %d", fa->fa_drive);
375 	return (QUIET);
376 }
377 
378 static void
379 fdconf(fdc)
380 	struct fdc_softc *fdc;
381 {
382 	int	vroom;
383 
384 	if (out_fdc(fdc, NE7CMD_DUMPREG) || fdcresult(fdc) != 10)
385 		return;
386 
387 	/*
388 	 * dumpreg[7] seems to be a motor-off timeout; set it to whatever
389 	 * the PROM thinks is appropriate.
390 	 */
391 	if ((vroom = fdc->sc_status[7]) == 0)
392 		vroom = 0x64;
393 
394 	/* Configure controller to use FIFO and Implied Seek */
395 	out_fdc(fdc, NE7CMD_CFG);
396 	out_fdc(fdc, vroom);
397 	out_fdc(fdc, fdc->sc_cfg);
398 	out_fdc(fdc, 0); /* PRETRK */
399 	/* No result phase */
400 }
401 
402 void
403 fdcattach(parent, self, aux)
404 	struct device *parent, *self;
405 	void *aux;
406 {
407 	struct confargs *ca = aux;
408 	struct fdc_softc *fdc = (void *)self;
409 	struct fdc_attach_args fa;
410 	int pri, vec;
411 	char code;
412 
413 	fdc->sc_reg = (caddr_t)bus_mapin(ca->ca_bustype, ca->ca_paddr,
414 		sizeof(union fdreg));
415 
416 	callout_init(&fdc->sc_timo_ch);
417 	callout_init(&fdc->sc_intr_ch);
418 
419 	fdc->sc_state = DEVIDLE;
420 	fdc->sc_istate = ISTATE_IDLE;
421 	fdc->sc_flags |= FDC_EIS;
422 	TAILQ_INIT(&fdc->sc_drives);
423 
424 	/* Assume a 82072 */
425 	code = '2';
426 
427 	if (code == '7') {
428 		panic("no 82077 fdc in this kernel");
429 		/* NOTREACHED */
430 	} else {
431 		fdc->sc_reg_msr = &((struct fdreg_72 *)fdc->sc_reg)->fd_msr;
432 		fdc->sc_reg_fifo = &((struct fdreg_72 *)fdc->sc_reg)->fd_fifo;
433 
434 		fdc->sc_reg_fcr = ((volatile u_int8_t *) fdc->sc_reg)
435 			+ FDC_FCR_OFFSET;
436 		fdc->sc_reg_fvr = ((volatile u_int8_t *) fdc->sc_reg)
437 			+ FDC_FVR_OFFSET;
438 	}
439 
440 	isr_add_autovect(fdcswintr, fdc, FDC_SOFTPRI);
441 	pri = ca->ca_intpri;
442 	vec = ca->ca_intvec;
443 	if (vec == -1) {
444 		/* Tell the FDC to fake an autovector. */
445 		vec = 0x18 + pri; /* XXX */
446 		isr_add_autovect(fdchwintr, fdc, pri);
447 	} else {
448 		/* An OBIO bus with vectors?  Weird exception. */
449 		isr_add_vectored(fdchwintr, fdc, pri, vec);
450 	}
451 	*fdc->sc_reg_fvr = vec;	/* Program controller w/ interrupt vector */
452 
453 	printf(": (softpri %d) chip 8207%c\n", FDC_SOFTPRI, code);
454 
455 #ifdef FD_DEBUG
456 	if (out_fdc(fdc, NE7CMD_VERSION) == 0 &&
457 	    fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x90) {
458 		if (fdc_debug)
459 			printf("[version cmd]");
460 	}
461 #endif
462 
463 	fdc_reset(fdc);
464 	/*
465 	 * Configure controller; enable FIFO, Implied seek, no POLL mode?.
466 	 * Note: CFG_EFIFO is active-low, initial threshold value: 8
467 	 */
468 	fdc->sc_cfg = CFG_EIS|/*CFG_EFIFO|*/CFG_POLL|(8 & CFG_THRHLD_MASK);
469 	fdconf(fdc);
470 
471 	evcnt_attach_dynamic(&fdc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
472 	    fdc->sc_dev.dv_xname, "intr");
473 
474 	/* physical limit: four drives per controller. */
475 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
476 		fa.fa_deftype = NULL;		/* unknown */
477 	fa.fa_deftype = &fd_types[0];		/* XXX */
478 		(void)config_found(self, (void *)&fa, fdprint);
479 	}
480 }
481 
482 int
483 fdmatch(parent, match, aux)
484 	struct device *parent;
485 	struct cfdata *match;
486 	void *aux;
487 {
488 	struct fdc_softc *fdc = (void *)parent;
489 	struct fdc_attach_args *fa = aux;
490 	int drive = fa->fa_drive;
491 	int n, ok;
492 
493 	if (drive > 0)
494 		/* XXX - for now, punt > 1 drives */
495 		return (0);
496 
497 	/* select drive and turn on motor */
498 	fdc->sc_fcr |= FCR_DSEL(drive) | FCR_MTRON;
499 	FCR_REG_SYNC();
500 	/* wait for motor to spin up */
501 	delay(250000);
502 
503 	fdc->sc_nstat = 0;
504 	out_fdc(fdc, NE7CMD_RECAL);
505 	out_fdc(fdc, drive);
506 	/* wait for recalibrate */
507 	for (n = 0; n < 10000; n++) {
508 		delay(1000);
509 		if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) {
510 			/* wait a bit longer till device *really* is ready */
511 			delay(100000);
512 			if (out_fdc(fdc, NE7CMD_SENSEI))
513 				break;
514 			if (fdcresult(fdc) == 1 && fdc->sc_status[0] == 0x80)
515 				/*
516 				 * Got `invalid command'; we interpret it
517 				 * to mean that the re-calibrate hasn't in
518 				 * fact finished yet
519 				 */
520 				continue;
521 			break;
522 		}
523 	}
524 	n = fdc->sc_nstat;
525 #ifdef FD_DEBUG
526 	if (fdc_debug) {
527 		int i;
528 		printf("fdprobe: %d stati:", n);
529 		for (i = 0; i < n; i++)
530 			printf(" %x", fdc->sc_status[i]);
531 		printf("\n");
532 	}
533 #endif
534 	ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0;
535 
536 	/* turn off motor */
537 	fdc->sc_fcr &= ~(FCR_DSEL(drive)|FCR_MTRON);
538 	FCR_REG_SYNC();
539 
540 	return (ok);
541 }
542 
543 /*
544  * Controller is working, and drive responded.  Attach it.
545  */
546 void
547 fdattach(parent, self, aux)
548 	struct device *parent, *self;
549 	void *aux;
550 {
551 	struct fdc_softc *fdc = (void *)parent;
552 	struct fd_softc *fd = (void *)self;
553 	struct fdc_attach_args *fa = aux;
554 	struct fd_type *type = fa->fa_deftype;
555 	int drive = fa->fa_drive;
556 
557 	callout_init(&fd->sc_motoron_ch);
558 	callout_init(&fd->sc_motoroff_ch);
559 
560 	/* XXX Allow `flags' to override device type? */
561 
562 	if (type)
563 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
564 		    type->tracks, type->heads, type->sectrac);
565 	else
566 		printf(": density unknown\n");
567 
568 	bufq_alloc(&fd->sc_q, BUFQ_DISKSORT|BUFQ_SORT_CYLINDER);
569 	fd->sc_cylin = -1;
570 	fd->sc_drive = drive;
571 	fd->sc_deftype = type;
572 	fdc->sc_fd[drive] = fd;
573 
574 	/*
575 	 * Initialize and attach the disk structure.
576 	 */
577 	fd->sc_dk.dk_name = fd->sc_dv.dv_xname;
578 	fd->sc_dk.dk_driver = &fddkdriver;
579 	disk_attach(&fd->sc_dk);
580 
581 #ifdef	sparc
582 	/*
583 	 * We're told if we're the boot device in fdcattach().
584 	 */
585 	if (fa->fa_bootpath)
586 		fa->fa_bootpath->dev = &fd->sc_dv;
587 #endif
588 #define	OUT_FDC(sc, c)	{                                \
589 	if (out_fdc((sc), (c)))                          \
590 		printf("fdc: specify command failed.\n");\
591 	}
592 	/* specify command */
593 	OUT_FDC(fdc, NE7CMD_SPECIFY);
594 	OUT_FDC(fdc, type->steprate);
595 	/*
596 	 * The '|1' in the following statement turns on the 'Non-DMA' bit
597 	 * specifier in the last byte of the SPECIFY command as described in the
598 	 * datasheet I have.  This is necessary for the driver to work on the
599 	 * sun3x, because the system will not respond to the chip's requests
600 	 * for DMA; there is no hardware on the motherboard to support it.
601 	 * By enabling this bit, we will force the chip to interrupt when its
602 	 * FIFO is full, at which point the interrupt handler will empty it and
603 	 * continue.  This is ``pseudo-DMA''.
604 	 * -J
605 	 */
606 	OUT_FDC(fdc, 6|1);	/* XXX head load time == 6ms */
607 #undef	OUT_FDC
608 
609 	/*
610 	 * Establish a mountroot_hook anyway in case we booted
611 	 * with RB_ASKNAME and get selected as the boot device.
612 	 */
613 	mountroothook_establish(fd_mountroot_hook, &fd->sc_dv);
614 
615 	/* Make sure the drive motor gets turned off at shutdown time. */
616 	fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd);
617 }
618 
619 __inline struct fd_type *
620 fd_dev_to_type(fd, dev)
621 	struct fd_softc *fd;
622 	dev_t dev;
623 {
624 	int type = FDTYPE(dev);
625 
626 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
627 		return (NULL);
628 	return (type ? &fd_types[type - 1] : fd->sc_deftype);
629 }
630 
631 void
632 fdstrategy(bp)
633 	struct buf *bp;			/* IO operation to perform */
634 {
635 	struct fd_softc *fd;
636 	int unit = FDUNIT(bp->b_dev);
637 	int sz;
638 	int s;
639 
640 	/* Valid unit, controller, and request? */
641 	if (unit >= fd_cd.cd_ndevs ||
642 	    (fd = fd_cd.cd_devs[unit]) == 0 ||
643 	    bp->b_blkno < 0 ||
644 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
645 	     (bp->b_flags & B_FORMAT) == 0)) {
646 		bp->b_error = EINVAL;
647 		goto bad;
648 	}
649 
650 	/* If it's a null transfer, return immediately. */
651 	if (bp->b_bcount == 0)
652 		goto done;
653 
654 	sz = howmany(bp->b_bcount, FDC_BSIZE);
655 
656 	if (bp->b_blkno + sz > fd->sc_type->size) {
657 		sz = fd->sc_type->size - bp->b_blkno;
658 		if (sz == 0) {
659 			/* If exactly at end of disk, return EOF. */
660 			bp->b_resid = bp->b_bcount;
661 			goto done;
662 		}
663 		if (sz < 0) {
664 			/* If past end of disk, return EINVAL. */
665 			bp->b_error = EINVAL;
666 			goto bad;
667 		}
668 		/* Otherwise, truncate request. */
669 		bp->b_bcount = sz << DEV_BSHIFT;
670 	}
671 
672 	bp->b_rawblkno = bp->b_blkno;
673 	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
674 
675 #ifdef FD_DEBUG
676 	if (fdc_debug > 1)
677 	    printf("fdstrategy: b_blkno %d b_bcount %ld blkno %d cylin %ld\n",
678 		    bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder);
679 #endif
680 
681 	/* Queue transfer on drive, activate drive and controller if idle. */
682 	s = splbio();
683 	BUFQ_PUT(&fd->sc_q, bp);
684 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
685 	if (fd->sc_active == 0)
686 		fdstart(fd);
687 #ifdef DIAGNOSTIC
688 	else {
689 		struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
690 		if (fdc->sc_state == DEVIDLE) {
691 			printf("fdstrategy: controller inactive\n");
692 			fdcstart(fdc);
693 		}
694 	}
695 #endif
696 	splx(s);
697 	return;
698 
699 bad:
700 	bp->b_flags |= B_ERROR;
701 done:
702 	/* Toss transfer; we're done early. */
703 	biodone(bp);
704 }
705 
706 void
707 fdstart(fd)
708 	struct fd_softc *fd;
709 {
710 	struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
711 	int active = fdc->sc_drives.tqh_first != 0;
712 
713 	/* Link into controller queue. */
714 	fd->sc_active = 1;
715 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
716 
717 	/* If controller not already active, start it. */
718 	if (!active)
719 		fdcstart(fdc);
720 }
721 
722 void
723 fdfinish(fd, bp)
724 	struct fd_softc *fd;
725 	struct buf *bp;
726 {
727 	struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
728 
729 	/*
730 	 * Move this drive to the end of the queue to give others a `fair'
731 	 * chance.  We only force a switch if N operations are completed while
732 	 * another drive is waiting to be serviced, since there is a long motor
733 	 * startup delay whenever we switch.
734 	 */
735 	(void)BUFQ_GET(&fd->sc_q);
736 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
737 		fd->sc_ops = 0;
738 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
739 		if (BUFQ_PEEK(&fd->sc_q) != NULL) {
740 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
741 		} else
742 			fd->sc_active = 0;
743 	}
744 	bp->b_resid = fd->sc_bcount;
745 	fd->sc_skip = 0;
746 
747 	biodone(bp);
748 	/* turn off motor 5s from now */
749 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
750 	fdc->sc_state = DEVIDLE;
751 }
752 
753 void
754 fdc_reset(fdc)
755 	struct fdc_softc *fdc;
756 {
757 	fdc->sc_fcr = 0;
758 	FCR_REG_SYNC();
759 
760 	*fdc->sc_reg_drs = DRS_RESET;
761 	delay(10);
762 	*fdc->sc_reg_drs = 0;
763 
764 #ifdef FD_DEBUG
765 	if (fdc_debug)
766 		printf("fdc reset\n");
767 #endif
768 }
769 
770 void
771 fd_set_motor(fdc)
772 	struct fdc_softc *fdc;
773 {
774 	struct fd_softc *fd;
775 	int n;
776 
777 	int on = 0;
778 
779 	for (n = 0; n < 4; n++)
780 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
781 			on = 1;
782 	if (on) {
783 		fdc->sc_fcr |= FCR_DSEL(0)|FCR_MTRON; /* XXX */
784 	} else {
785 		fdc->sc_fcr &= ~(FCR_DSEL(0)|FCR_MTRON); /* XXX */
786 	}
787 	FCR_REG_SYNC();
788 }
789 
790 void
791 fd_motor_off(arg)
792 	void *arg;
793 {
794 	struct fd_softc *fd = arg;
795 	int s;
796 
797 	s = splbio();
798 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
799 	fd_set_motor((struct fdc_softc *)fd->sc_dv.dv_parent);
800 	splx(s);
801 }
802 
803 void
804 fd_motor_on(arg)
805 	void *arg;
806 {
807 	struct fd_softc *fd = arg;
808 	struct fdc_softc *fdc = (void *)fd->sc_dv.dv_parent;
809 	int s;
810 
811 	s = splbio();
812 	fd->sc_flags &= ~FD_MOTOR_WAIT;
813 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
814 		(void) fdcstate(fdc);
815 	splx(s);
816 }
817 
818 int
819 fdcresult(fdc)
820 	struct fdc_softc *fdc;
821 {
822 	u_char i;
823 	int j = 100000,
824 	    n = 0;
825 
826 	for (; j; j--) {
827 		i = *fdc->sc_reg_msr & (NE7_DIO | NE7_RQM | NE7_CB);
828 		if (i == NE7_RQM)
829 			return (fdc->sc_nstat = n);
830 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
831 			if (n >= sizeof(fdc->sc_status)) {
832 				log(LOG_ERR, "fdcresult: overrun\n");
833 				return (-1);
834 			}
835 			fdc->sc_status[n++] = *fdc->sc_reg_fifo;
836 		} else
837 			delay(10);
838 	}
839 	log(LOG_ERR, "fdcresult: timeout\n");
840 	return (fdc->sc_nstat = -1);
841 }
842 
843 int
844 out_fdc(fdc, x)
845 	struct fdc_softc *fdc;
846 	u_char x;
847 {
848 	int i = 100000;
849 
850 	while (((*fdc->sc_reg_msr & (NE7_DIO|NE7_RQM)) != NE7_RQM) && i-- > 0)
851 		delay(1);
852 	if (i <= 0)
853 		return (-1);
854 
855 	*fdc->sc_reg_fifo = x;
856 	return (0);
857 }
858 
859 int
860 fdopen(dev, flags, fmt, p)
861 	dev_t dev;
862 	int flags, fmt;
863 	struct proc *p;
864 {
865 	int unit, pmask;
866 	struct fd_softc *fd;
867 	struct fd_type *type;
868 
869 	unit = FDUNIT(dev);
870 	if (unit >= fd_cd.cd_ndevs)
871 		return (ENXIO);
872 	fd = fd_cd.cd_devs[unit];
873 	if (fd == 0)
874 		return (ENXIO);
875 	type = fd_dev_to_type(fd, dev);
876 	if (type == NULL)
877 		return (ENXIO);
878 
879 	if ((fd->sc_flags & FD_OPEN) != 0 &&
880 	    fd->sc_type != type)
881 		return (EBUSY);
882 
883 	fd->sc_type = type;
884 	fd->sc_cylin = -1;
885 	fd->sc_flags |= FD_OPEN;
886 
887 	/*
888 	 * Only update the disklabel if we're not open anywhere else.
889 	 */
890 	if (fd->sc_dk.dk_openmask == 0)
891 		fdgetdisklabel(dev);
892 
893 	pmask = (1 << DISKPART(dev));
894 
895 	switch (fmt) {
896 	case S_IFCHR:
897 		fd->sc_dk.dk_copenmask |= pmask;
898 		break;
899 
900 	case S_IFBLK:
901 		fd->sc_dk.dk_bopenmask |= pmask;
902 		break;
903 	}
904 	fd->sc_dk.dk_openmask =
905 	    fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
906 
907 	return (0);
908 }
909 
910 int
911 fdclose(dev, flags, fmt, p)
912 	dev_t dev;
913 	int flags, fmt;
914 	struct proc *p;
915 {
916 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
917 	int pmask = (1 << DISKPART(dev));
918 
919 	fd->sc_flags &= ~FD_OPEN;
920 	fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
921 
922 	switch (fmt) {
923 	case S_IFCHR:
924 		fd->sc_dk.dk_copenmask &= ~pmask;
925 		break;
926 
927 	case S_IFBLK:
928 		fd->sc_dk.dk_bopenmask &= ~pmask;
929 		break;
930 	}
931 	fd->sc_dk.dk_openmask =
932 	    fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask;
933 
934 	return (0);
935 }
936 
937 int
938 fdread(dev, uio, flag)
939 	dev_t dev;
940 	struct uio *uio;
941 	int flag;
942 {
943 
944 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
945 }
946 
947 int
948 fdwrite(dev, uio, flag)
949 	dev_t dev;
950 	struct uio *uio;
951 	int flag;
952 {
953 
954 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
955 }
956 
957 void
958 fdcstart(fdc)
959 	struct fdc_softc *fdc;
960 {
961 
962 #ifdef DIAGNOSTIC
963 	/* only got here if controller's drive queue was inactive; should
964 	   be in idle state */
965 	if (fdc->sc_state != DEVIDLE) {
966 		printf("fdcstart: not idle\n");
967 		return;
968 	}
969 #endif
970 	(void) fdcstate(fdc);
971 }
972 
973 void
974 fdcstatus(dv, n, s)
975 	struct device *dv;
976 	int n;
977 	char *s;
978 {
979 	struct fdc_softc *fdc = (void *)dv->dv_parent;
980 	char bits[64];
981 #if 0
982 	/*
983 	 * A 82072 seems to return <invalid command> on
984 	 * gratuitous Sense Interrupt commands.
985 	 */
986 	if (n == 0 && (fdc->sc_flags & FDC_82077)) {
987 		out_fdc(fdc, NE7CMD_SENSEI);
988 		(void) fdcresult(fdc);
989 		n = 2;
990 	}
991 #endif
992 
993 	/* Just print last status */
994 	n = fdc->sc_nstat;
995 
996 	printf("%s: %s: state %d", dv->dv_xname, s, fdc->sc_state);
997 
998 	switch (n) {
999 	case 0:
1000 		printf("\n");
1001 		break;
1002 	case 2:
1003 		printf(" (st0 %s cyl %d)\n",
1004 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
1005 		    bits, sizeof(bits)), fdc->sc_status[1]);
1006 		break;
1007 	case 7:
1008 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1009 		    NE7_ST0BITS, bits, sizeof(bits)));
1010 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1011 		    NE7_ST1BITS, bits, sizeof(bits)));
1012 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1013 		    NE7_ST2BITS, bits, sizeof(bits)));
1014 		printf(" cyl %d head %d sec %d)\n",
1015 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
1016 		break;
1017 #ifdef DIAGNOSTIC
1018 	default:
1019 		printf(" fdcstatus: weird size: %d\n", n);
1020 		break;
1021 #endif
1022 	}
1023 }
1024 
1025 void
1026 fdctimeout(arg)
1027 	void *arg;
1028 {
1029 	struct fdc_softc *fdc = arg;
1030 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
1031 	int s;
1032 
1033 	s = splbio();
1034 	fdcstatus(&fd->sc_dv, 0, "timeout");
1035 
1036 	if (BUFQ_PEEK(&fd->sc_q) != NULL)
1037 		fdc->sc_state++;
1038 	else
1039 		fdc->sc_state = DEVIDLE;
1040 
1041 	(void) fdcstate(fdc);
1042 	splx(s);
1043 }
1044 
1045 void
1046 fdcpseudointr(arg)
1047 	void *arg;
1048 {
1049 	struct fdc_softc *fdc = arg;
1050 	int s;
1051 
1052 	/* Just ensure it has the right spl. */
1053 	s = splbio();
1054 	(void) fdcstate(fdc);
1055 	splx(s);
1056 }
1057 
1058 
1059 /*
1060  * hardware interrupt entry point: must be converted to `fast'
1061  * (in-window) handler.
1062  */
1063 int
1064 fdchwintr(arg)
1065 	void *arg;
1066 {
1067 	struct fdc_softc *fdc = arg;
1068 
1069 	/*
1070 	 * This code was reverse engineered from the SPARC bsd_fdintr.s.
1071 	 */
1072 	switch (fdc->sc_istate) {
1073 	case ISTATE_IDLE:
1074 		return (0);
1075 	case ISTATE_SENSEI:
1076 		out_fdc(fdc, NE7CMD_SENSEI);
1077 		fdcresult(fdc);
1078 		fdc->sc_istate = ISTATE_DONE;
1079 		FD_SET_SWINTR();
1080 		return (1);
1081 	case ISTATE_DMA:
1082 		break;
1083 	default:
1084 		log(LOG_ERR, "fdc: stray hard interrupt.\n");
1085 		fdc->sc_fcr &= ~(FCR_DSEL(0));	/* Does this help? */
1086 		fdc->sc_istate = ISTATE_SPURIOUS;
1087 		FD_SET_SWINTR();
1088 		return (1);
1089 	}
1090 
1091 	for (;;) {
1092 		int msr;
1093 
1094 		msr = *fdc->sc_reg_msr;
1095 
1096 		if ((msr & NE7_RQM) == 0)
1097 			break;
1098 
1099 		if ((msr & NE7_NDM) == 0) {
1100 			fdcresult(fdc);
1101 			fdc->sc_istate = ISTATE_DONE;
1102 			FD_SET_SWINTR();
1103 			log(LOG_ERR, "fdc: overrun: tc = %d\n", fdc->sc_tc);
1104 			break;
1105 		}
1106 
1107 		if (msr & NE7_DIO) {
1108 			*fdc->sc_data++ = *fdc->sc_reg_fifo;
1109 		} else {
1110 			*fdc->sc_reg_fifo = *fdc->sc_data++;
1111 		}
1112 		if (--fdc->sc_tc == 0) {
1113 			fdc->sc_fcr |= FCR_TC;
1114 			FCR_REG_SYNC();
1115 			fdc->sc_istate = ISTATE_DONE;
1116 			delay(10);
1117 			fdc->sc_fcr &= ~FCR_TC;
1118 			FCR_REG_SYNC();
1119 			fdcresult(fdc);
1120 			FD_SET_SWINTR();
1121 			break;
1122 		}
1123 	}
1124 	return (1);
1125 }
1126 
1127 int
1128 fdcswintr(arg)
1129 	void *arg;
1130 {
1131 	struct fdc_softc *fdc = arg;
1132 	int s;
1133 
1134 	if (fdc_softpend == 0)
1135 		return (0);
1136 
1137 	isr_soft_clear(FDC_SOFTPRI);
1138 	fdc_softpend = 0;
1139 
1140 	if (fdc->sc_istate != ISTATE_DONE)
1141 		return (0);
1142 
1143 	fdc->sc_istate = ISTATE_IDLE;
1144 	s = splbio();
1145 	fdcstate(fdc);
1146 	splx(s);
1147 	return (1);
1148 }
1149 
1150 int
1151 fdcstate(fdc)
1152 	struct fdc_softc *fdc;
1153 {
1154 #define	st0	fdc->sc_status[0]
1155 #define	st1	fdc->sc_status[1]
1156 #define	cyl	fdc->sc_status[1]
1157 #define OUT_FDC(fdc, c, s) \
1158     do { if (out_fdc(fdc, (c))) { (fdc)->sc_state = (s); goto loop; } } while(0)
1159 
1160 	struct fd_softc *fd;
1161 	struct buf *bp;
1162 	int read, head, sec, nblks;
1163 	struct fd_type *type;
1164 	struct ne7_fd_formb *finfo = NULL;
1165 
1166 
1167 	if (fdc->sc_istate != ISTATE_IDLE) {
1168 		/* Trouble... */
1169 		printf("fdc: spurious interrupt: state %d, istate=%d\n",
1170 			fdc->sc_state, fdc->sc_istate);
1171 		fdc->sc_istate = ISTATE_IDLE;
1172 		if (fdc->sc_state == RESETCOMPLETE ||
1173 		    fdc->sc_state == RESETTIMEDOUT) {
1174 			panic("fdcintr: spurious interrupt can't be cleared");
1175 		}
1176 		goto doreset;
1177 	}
1178 
1179 loop:
1180 	/* Is there a drive for the controller to do a transfer with? */
1181 	fd = fdc->sc_drives.tqh_first;
1182 	if (fd == NULL) {
1183 		fdc->sc_state = DEVIDLE;
1184 		return (0);
1185 	}
1186 
1187 	/* Is there a transfer to this drive?  If not, deactivate drive. */
1188 	bp = BUFQ_PEEK(&fd->sc_q);
1189 	if (bp == NULL) {
1190 		fd->sc_ops = 0;
1191 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
1192 		fd->sc_active = 0;
1193 		goto loop;
1194 	}
1195 
1196 	if (bp->b_flags & B_FORMAT)
1197 		finfo = (struct ne7_fd_formb *)bp->b_data;
1198 
1199 	switch (fdc->sc_state) {
1200 	case DEVIDLE:
1201 		fdc->sc_errors = 0;
1202 		fd->sc_skip = 0;
1203 		fd->sc_bcount = bp->b_bcount;
1204 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
1205 		callout_stop(&fd->sc_motoroff_ch);
1206 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
1207 			fdc->sc_state = MOTORWAIT;
1208 			return (1);
1209 		}
1210 		if ((fd->sc_flags & FD_MOTOR) == 0) {
1211 			/* Turn on the motor, being careful about pairing. */
1212 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
1213 			if (ofd && ofd->sc_flags & FD_MOTOR) {
1214 				callout_stop(&ofd->sc_motoroff_ch);
1215 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
1216 			}
1217 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
1218 			fd_set_motor(fdc);
1219 			fdc->sc_state = MOTORWAIT;
1220 			if (fdc->sc_flags & FDC_82077) { /* XXX */
1221 				/* Allow .25s for motor to stabilize. */
1222 				callout_reset(&fd->sc_motoron_ch, hz / 4,
1223 				    fd_motor_on, fd);
1224 			} else {
1225 				fd->sc_flags &= ~FD_MOTOR_WAIT;
1226 				goto loop;
1227 			}
1228 			return (1);
1229 		}
1230 		/* Make sure the right drive is selected. */
1231 		fd_set_motor(fdc);
1232 
1233 		/*FALLTHROUGH*/
1234 	case DOSEEK:
1235 	doseek:
1236 		if ((fdc->sc_flags & FDC_EIS) &&
1237 		    (bp->b_flags & B_FORMAT) == 0) {
1238 			fd->sc_cylin = bp->b_cylinder;
1239 			/* We use implied seek */
1240 			goto doio;
1241 		}
1242 
1243 		if (fd->sc_cylin == bp->b_cylinder)
1244 			goto doio;
1245 
1246 		/* specify command */
1247 		OUT_FDC(fdc, NE7CMD_SPECIFY, SEEKTIMEDOUT);
1248 		OUT_FDC(fdc, fd->sc_type->steprate, SEEKTIMEDOUT);
1249 		OUT_FDC(fdc, 6|1, SEEKTIMEDOUT);	/* XXX head load time == 6ms */
1250 
1251 		fdc->sc_istate = ISTATE_SENSEI;
1252 		/* seek function */
1253 		OUT_FDC(fdc, NE7CMD_SEEK, SEEKTIMEDOUT);
1254 		OUT_FDC(fdc, fd->sc_drive, SEEKTIMEDOUT); /* drive number */
1255 		OUT_FDC(fdc, bp->b_cylinder * fd->sc_type->step, SEEKTIMEDOUT);
1256 
1257 		fd->sc_cylin = -1;
1258 		fdc->sc_state = SEEKWAIT;
1259 		fdc->sc_nstat = 0;
1260 
1261 		fd->sc_dk.dk_seek++;
1262 		disk_busy(&fd->sc_dk);
1263 
1264 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1265 		return (1);
1266 
1267 	case DOIO:
1268 	doio:
1269 #ifdef	NOTYET
1270 		/* Check to see if the disk has changed */
1271 		if (fdc->sc_reg_dir & FDI_DCHG) {
1272 			/*
1273 			 * The disk in the drive has changed since
1274 			 * the last transfer.  We need to see if its geometry
1275 			 * has changed.
1276 			 */
1277 		}
1278 #endif	/* NOTYET */
1279 
1280 		if (finfo)
1281 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1282 				      (char *)finfo;
1283 		type = fd->sc_type;
1284 		sec = fd->sc_blkno % type->seccyl;
1285 		nblks = type->seccyl - sec;
1286 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1287 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1288 		fd->sc_nblks = nblks;
1289 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1290 		head = sec / type->sectrac;
1291 		sec -= head * type->sectrac;
1292 #ifdef DIAGNOSTIC
1293 		{int block;
1294 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
1295 		 if (block != fd->sc_blkno) {
1296 			 printf("fdcintr: block %d != blkno %" PRIu64 "\n",
1297 				block, fd->sc_blkno);
1298 #ifdef DDB
1299 			 Debugger();
1300 #endif
1301 		 }}
1302 #endif
1303 		read = bp->b_flags & B_READ;
1304 
1305 		/* Setup for pseudo DMA */
1306 		fdc->sc_data = bp->b_data + fd->sc_skip;
1307 		fdc->sc_tc = fd->sc_nbytes;
1308 
1309 		*fdc->sc_reg_drs = type->rate;
1310 #ifdef FD_DEBUG
1311 		if (fdc_debug > 1)
1312 			printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1313 				read ? "read" : "write", fd->sc_drive,
1314 				fd->sc_cylin, head, sec, nblks);
1315 #endif
1316 		fdc->sc_state = IOCOMPLETE;
1317 		fdc->sc_istate = ISTATE_DMA;
1318 		fdc->sc_nstat = 0;
1319 		if (finfo) {
1320 			/* formatting */
1321 			OUT_FDC(fdc, NE7CMD_FORMAT, IOTIMEDOUT);
1322 			OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
1323 			OUT_FDC(fdc, finfo->fd_formb_secshift, IOTIMEDOUT);
1324 			OUT_FDC(fdc, finfo->fd_formb_nsecs, IOTIMEDOUT);
1325 			OUT_FDC(fdc, finfo->fd_formb_gaplen, IOTIMEDOUT);
1326 			OUT_FDC(fdc, finfo->fd_formb_fillbyte, IOTIMEDOUT);
1327 		} else {
1328 			if (read)
1329 				OUT_FDC(fdc, NE7CMD_READ, IOTIMEDOUT);
1330 			else
1331 				OUT_FDC(fdc, NE7CMD_WRITE, IOTIMEDOUT);
1332 			OUT_FDC(fdc, (head << 2) | fd->sc_drive, IOTIMEDOUT);
1333 			OUT_FDC(fdc, fd->sc_cylin, IOTIMEDOUT);	/*track*/
1334 			OUT_FDC(fdc, head, IOTIMEDOUT);
1335 			OUT_FDC(fdc, sec + 1, IOTIMEDOUT);	/*sector+1*/
1336 			OUT_FDC(fdc, type->secsize, IOTIMEDOUT);/*sector size*/
1337 			OUT_FDC(fdc, type->sectrac, IOTIMEDOUT);/*secs/track*/
1338 			OUT_FDC(fdc, type->gap1, IOTIMEDOUT);	/*gap1 size*/
1339 			OUT_FDC(fdc, type->datalen, IOTIMEDOUT);/*data length*/
1340 		}
1341 
1342 		disk_busy(&fd->sc_dk);
1343 
1344 		/* allow 2 seconds for operation */
1345 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1346 		return (1);				/* will return later */
1347 
1348 	case SEEKWAIT:
1349 		callout_stop(&fdc->sc_timo_ch);
1350 		fdc->sc_state = SEEKCOMPLETE;
1351 		if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1352 			/* allow 1/50 second for heads to settle */
1353 			callout_reset(&fdc->sc_intr_ch, hz / 50,
1354 			    fdcpseudointr, fdc);
1355 			return (1);		/* will return later */
1356 		}
1357 		/*FALLTHROUGH*/
1358 	case SEEKCOMPLETE:
1359 		/* no data on seek */
1360 		disk_unbusy(&fd->sc_dk, 0, 0);
1361 
1362 		/* Make sure seek really happened. */
1363 		if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 ||
1364 		    cyl != bp->b_cylinder * fd->sc_type->step) {
1365 #ifdef FD_DEBUG
1366 			if (fdc_debug)
1367 				fdcstatus(&fd->sc_dv, 2, "seek failed");
1368 #endif
1369 			fdcretry(fdc);
1370 			goto loop;
1371 		}
1372 		fd->sc_cylin = bp->b_cylinder;
1373 		goto doio;
1374 
1375 	case IOTIMEDOUT:
1376 		fdc->sc_fcr |= FCR_TC;
1377 		FCR_REG_SYNC();
1378 		delay(10);
1379 		fdc->sc_fcr &= ~FCR_TC;
1380 		FCR_REG_SYNC();
1381 		(void)fdcresult(fdc);
1382 		/*FALLTHROUGH*/
1383 	case SEEKTIMEDOUT:
1384 	case RECALTIMEDOUT:
1385 	case RESETTIMEDOUT:
1386 		fdcretry(fdc);
1387 		goto loop;
1388 
1389 	case IOCOMPLETE: /* IO DONE, post-analyze */
1390 		callout_stop(&fdc->sc_timo_ch);
1391 
1392 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1393 		    (bp->b_flags & B_READ));
1394 
1395 		if (fdc->sc_nstat != 7 || (st0 & 0xf8) != 0 || st1 != 0) {
1396 #ifdef FD_DEBUG
1397 			if (fdc_debug) {
1398 				fdcstatus(&fd->sc_dv, 7,
1399 					bp->b_flags & B_READ
1400 					? "read failed" : "write failed");
1401 				printf("blkno %d nblks %d tc %d\n",
1402 				       fd->sc_blkno, fd->sc_nblks, fdc->sc_tc);
1403 			}
1404 #endif
1405 			if (fdc->sc_nstat == 7 &&
1406 			    (st1 & ST1_OVERRUN) == ST1_OVERRUN) {
1407 
1408 				/*
1409 				 * Silently retry overruns if no other
1410 				 * error bit is set. Adjust threshold.
1411 				 */
1412 				int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1413 				if (thr < 15) {
1414 					thr++;
1415 					fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1416 					fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1417 #ifdef FD_DEBUG
1418 					if (fdc_debug)
1419 						printf("fdc: %d -> threshold\n", thr);
1420 #endif
1421 					fdconf(fdc);
1422 					fdc->sc_overruns = 0;
1423 				}
1424 				if (++fdc->sc_overruns < 3) {
1425 					fdc->sc_state = DOIO;
1426 					goto loop;
1427 				}
1428 			}
1429 			fdcretry(fdc);
1430 			goto loop;
1431 		}
1432 		if (fdc->sc_errors) {
1433 			diskerr(bp, "fd", "soft error", LOG_PRINTF,
1434 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1435 			printf("\n");
1436 			fdc->sc_errors = 0;
1437 		} else {
1438 			if (--fdc->sc_overruns < -20) {
1439 				int thr = fdc->sc_cfg & CFG_THRHLD_MASK;
1440 				if (thr > 0) {
1441 					thr--;
1442 					fdc->sc_cfg &= ~CFG_THRHLD_MASK;
1443 					fdc->sc_cfg |= (thr & CFG_THRHLD_MASK);
1444 #ifdef FD_DEBUG
1445 					if (fdc_debug)
1446 						printf("fdc: %d -> threshold\n", thr);
1447 #endif
1448 					fdconf(fdc);
1449 				}
1450 				fdc->sc_overruns = 0;
1451 			}
1452 		}
1453 		fd->sc_blkno += fd->sc_nblks;
1454 		fd->sc_skip += fd->sc_nbytes;
1455 		fd->sc_bcount -= fd->sc_nbytes;
1456 		if (!finfo && fd->sc_bcount > 0) {
1457 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1458 			goto doseek;
1459 		}
1460 		fdfinish(fd, bp);
1461 		goto loop;
1462 
1463 	case DORESET:
1464 	doreset:
1465 		/* try a reset, keep motor on */
1466 		fd_set_motor(fdc);
1467 		delay(100);
1468 		fdc_reset(fdc);
1469 		fdc->sc_nstat = 0;
1470 		fdc->sc_istate = ISTATE_SENSEI;
1471 		fdc->sc_state = RESETCOMPLETE;
1472 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1473 		return (1);			/* will return later */
1474 
1475 	case RESETCOMPLETE:
1476 		callout_stop(&fdc->sc_timo_ch);
1477 		fdconf(fdc);
1478 
1479 		/* fall through */
1480 	case DORECAL:
1481 		fdc->sc_state = RECALWAIT;
1482 		fdc->sc_istate = ISTATE_SENSEI;
1483 		fdc->sc_nstat = 0;
1484 		/* recalibrate function */
1485 		OUT_FDC(fdc, NE7CMD_RECAL, RECALTIMEDOUT);
1486 		OUT_FDC(fdc, fd->sc_drive, RECALTIMEDOUT);
1487 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1488 		return (1);			/* will return later */
1489 
1490 	case RECALWAIT:
1491 		callout_stop(&fdc->sc_timo_ch);
1492 		fdc->sc_state = RECALCOMPLETE;
1493 		if (fdc->sc_flags & FDC_NEEDHEADSETTLE) {
1494 			/* allow 1/30 second for heads to settle */
1495 			callout_reset(&fdc->sc_intr_ch, hz / 30,
1496 			    fdcpseudointr, fdc);
1497 			return (1);		/* will return later */
1498 		}
1499 
1500 	case RECALCOMPLETE:
1501 		if (fdc->sc_nstat != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1502 #ifdef FD_DEBUG
1503 			if (fdc_debug)
1504 				fdcstatus(&fd->sc_dv, 2, "recalibrate failed");
1505 #endif
1506 			fdcretry(fdc);
1507 			goto loop;
1508 		}
1509 		fd->sc_cylin = 0;
1510 		goto doseek;
1511 
1512 	case MOTORWAIT:
1513 		if (fd->sc_flags & FD_MOTOR_WAIT)
1514 			return (1);		/* time's not up yet */
1515 		goto doseek;
1516 
1517 	default:
1518 		fdcstatus(&fd->sc_dv, 0, "stray interrupt");
1519 		return (1);
1520 	}
1521 #ifdef DIAGNOSTIC
1522 	panic("fdcintr: impossible");
1523 #endif
1524 #undef	st0
1525 #undef	st1
1526 #undef	cyl
1527 }
1528 
1529 void
1530 fdcretry(fdc)
1531 	struct fdc_softc *fdc;
1532 {
1533 	char bits[64];
1534 	struct fd_softc *fd;
1535 	struct buf *bp;
1536 
1537 	fd = fdc->sc_drives.tqh_first;
1538 	bp = BUFQ_PEEK(&fd->sc_q);
1539 
1540 	fdc->sc_overruns = 0;
1541 	if (fd->sc_opts & FDOPT_NORETRY)
1542 		goto fail;
1543 
1544 	switch (fdc->sc_errors) {
1545 	case 0:
1546 		/* try again */
1547 		fdc->sc_state =
1548 			(fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK;
1549 		break;
1550 
1551 	case 1: case 2: case 3:
1552 		/* didn't work; try recalibrating */
1553 		fdc->sc_state = DORECAL;
1554 		break;
1555 
1556 	case 4:
1557 		/* still no go; reset the bastard */
1558 		fdc->sc_state = DORESET;
1559 		break;
1560 
1561 	default:
1562 	fail:
1563 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1564 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
1565 				fd->sc_skip / FDC_BSIZE,
1566 				(struct disklabel *)NULL);
1567 
1568 			printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
1569 				NE7_ST0BITS, bits, sizeof(bits)));
1570 			printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
1571 				NE7_ST1BITS, bits, sizeof(bits)));
1572 			printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
1573 				NE7_ST2BITS, bits, sizeof(bits)));
1574 			printf(" cyl %d head %d sec %d)\n",
1575 				fdc->sc_status[3], fdc->sc_status[4],
1576 				fdc->sc_status[5]);
1577 		}
1578 
1579 		bp->b_flags |= B_ERROR;
1580 		bp->b_error = EIO;
1581 		fdfinish(fd, bp);
1582 	}
1583 	fdc->sc_errors++;
1584 }
1585 
1586 int
1587 fdioctl(dev, cmd, addr, flag, p)
1588 	dev_t dev;
1589 	u_long cmd;
1590 	caddr_t addr;
1591 	int flag;
1592 	struct proc *p;
1593 {
1594 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1595 	struct fdformat_parms *form_parms;
1596 	struct fdformat_cmd *form_cmd;
1597 	struct ne7_fd_formb *fd_formb;
1598 	int il[FD_MAX_NSEC + 1];
1599 	int i, j;
1600 	int error;
1601 
1602 	switch (cmd) {
1603 	case DIOCGDINFO:
1604 		*(struct disklabel *)addr = *(fd->sc_dk.dk_label);
1605 		return 0;
1606 
1607 	case DIOCWLABEL:
1608 		if ((flag & FWRITE) == 0)
1609 			return EBADF;
1610 		/* XXX do something */
1611 		return (0);
1612 
1613 	case DIOCWDINFO:
1614 		if ((flag & FWRITE) == 0)
1615 			return (EBADF);
1616 
1617 		error = setdisklabel(fd->sc_dk.dk_label,
1618 				    (struct disklabel *)addr, 0,
1619 				    fd->sc_dk.dk_cpulabel);
1620 		if (error)
1621 			return (error);
1622 
1623 		error = writedisklabel(dev, fdstrategy,
1624 				       fd->sc_dk.dk_label,
1625 				       fd->sc_dk.dk_cpulabel);
1626 		return (error);
1627 
1628 	case DIOCLOCK:
1629 		/*
1630 		 * Nothing to do here, really.
1631 		 */
1632 		return (0);
1633 
1634 	case DIOCEJECT:
1635 		if (*(int *)addr == 0) {
1636 			int part = DISKPART(dev);
1637 			/*
1638 			 * Don't force eject: check that we are the only
1639 			 * partition open. If so, unlock it.
1640 			 */
1641 			if ((fd->sc_dk.dk_openmask & ~(1 << part)) != 0 ||
1642 			    fd->sc_dk.dk_bopenmask + fd->sc_dk.dk_copenmask !=
1643 			    fd->sc_dk.dk_openmask) {
1644 				return (EBUSY);
1645 			}
1646 		}
1647 		/* FALLTHROUGH */
1648 	case ODIOCEJECT:
1649 		fd_do_eject((void *)fd->sc_dv.dv_parent, fd->sc_drive);
1650 		return (0);
1651 
1652 	case FDIOCGETFORMAT:
1653 		form_parms = (struct fdformat_parms *)addr;
1654 		form_parms->fdformat_version = FDFORMAT_VERSION;
1655 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1656 		form_parms->ncyl = fd->sc_type->tracks;
1657 		form_parms->nspt = fd->sc_type->sectrac;
1658 		form_parms->ntrk = fd->sc_type->heads;
1659 		form_parms->stepspercyl = fd->sc_type->step;
1660 		form_parms->gaplen = fd->sc_type->gap2;
1661 		form_parms->fillbyte = fd->sc_type->fillbyte;
1662 		form_parms->interleave = fd->sc_type->interleave;
1663 		switch (fd->sc_type->rate) {
1664 		case FDC_500KBPS:
1665 			form_parms->xfer_rate = 500 * 1024;
1666 			break;
1667 		case FDC_300KBPS:
1668 			form_parms->xfer_rate = 300 * 1024;
1669 			break;
1670 		case FDC_250KBPS:
1671 			form_parms->xfer_rate = 250 * 1024;
1672 			break;
1673 		default:
1674 			return (EINVAL);
1675 		}
1676 		return (0);
1677 
1678 	case FDIOCSETFORMAT:
1679 		if ((flag & FWRITE) == 0)
1680 			return (EBADF);	/* must be opened for writing */
1681 
1682 		form_parms = (struct fdformat_parms *)addr;
1683 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
1684 			return (EINVAL);/* wrong version of formatting prog */
1685 
1686 		i = form_parms->nbps >> 7;
1687 		if ((form_parms->nbps & 0x7f) || ffs(i) == 0 ||
1688 		    i & ~(1 << (ffs(i)-1)))
1689 			/* not a power-of-two multiple of 128 */
1690 			return (EINVAL);
1691 
1692 		switch (form_parms->xfer_rate) {
1693 		case 500 * 1024:
1694 			fd->sc_type->rate = FDC_500KBPS;
1695 			break;
1696 		case 300 * 1024:
1697 			fd->sc_type->rate = FDC_300KBPS;
1698 			break;
1699 		case 250 * 1024:
1700 			fd->sc_type->rate = FDC_250KBPS;
1701 			break;
1702 		default:
1703 			return (EINVAL);
1704 		}
1705 
1706 		if (form_parms->nspt > FD_MAX_NSEC ||
1707 		    form_parms->fillbyte > 0xff ||
1708 		    form_parms->interleave > 0xff)
1709 			return EINVAL;
1710 		fd->sc_type->sectrac = form_parms->nspt;
1711 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1712 			return EINVAL;
1713 		fd->sc_type->heads = form_parms->ntrk;
1714 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1715 		fd->sc_type->secsize = ffs(i)-1;
1716 		fd->sc_type->gap2 = form_parms->gaplen;
1717 		fd->sc_type->tracks = form_parms->ncyl;
1718 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1719 			form_parms->nbps / DEV_BSIZE;
1720 		fd->sc_type->step = form_parms->stepspercyl;
1721 		fd->sc_type->fillbyte = form_parms->fillbyte;
1722 		fd->sc_type->interleave = form_parms->interleave;
1723 		return (0);
1724 
1725 	case FDIOCFORMAT_TRACK:
1726 		if((flag & FWRITE) == 0)
1727 			/* must be opened for writing */
1728 			return (EBADF);
1729 		form_cmd = (struct fdformat_cmd *)addr;
1730 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1731 			/* wrong version of formatting prog */
1732 			return (EINVAL);
1733 
1734 		if (form_cmd->head >= fd->sc_type->heads ||
1735 		    form_cmd->cylinder >= fd->sc_type->tracks) {
1736 			return (EINVAL);
1737 		}
1738 
1739 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
1740 		    M_TEMP, M_NOWAIT);
1741 		if (fd_formb == 0)
1742 			return (ENOMEM);
1743 
1744 		fd_formb->head = form_cmd->head;
1745 		fd_formb->cyl = form_cmd->cylinder;
1746 		fd_formb->transfer_rate = fd->sc_type->rate;
1747 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1748 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1749 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1750 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1751 
1752 		memset(il, 0, sizeof(il));
1753 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1754 			while (il[(j%fd_formb->fd_formb_nsecs) + 1])
1755 				j++;
1756 			il[(j%fd_formb->fd_formb_nsecs) + 1] = i;
1757 			j += fd->sc_type->interleave;
1758 		}
1759 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1760 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1761 			fd_formb->fd_formb_headno(i) = form_cmd->head;
1762 			fd_formb->fd_formb_secno(i) = il[i+1];
1763 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1764 		}
1765 
1766 		error = fdformat(dev, fd_formb, p);
1767 		free(fd_formb, M_TEMP);
1768 		return (error);
1769 
1770 	case FDIOCGETOPTS:		/* get drive options */
1771 		*(int *)addr = fd->sc_opts;
1772 		return (0);
1773 
1774 	case FDIOCSETOPTS:		/* set drive options */
1775 		fd->sc_opts = *(int *)addr;
1776 		return (0);
1777 
1778 #ifdef DEBUG
1779 	case _IO('f', 100):
1780 		{
1781 		int i;
1782 		struct fdc_softc *fdc = (struct fdc_softc *)
1783 					fd->sc_dv.dv_parent;
1784 
1785 		out_fdc(fdc, NE7CMD_DUMPREG);
1786 		fdcresult(fdc);
1787 		printf("dumpreg(%d regs): <", fdc->sc_nstat);
1788 		for (i = 0; i < fdc->sc_nstat; i++)
1789 			printf(" %x", fdc->sc_status[i]);
1790 		printf(">\n");
1791 		}
1792 
1793 		return (0);
1794 	case _IOW('f', 101, int):
1795 		((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg &=
1796 			~CFG_THRHLD_MASK;
1797 		((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg |=
1798 			(*(int *)addr & CFG_THRHLD_MASK);
1799 		fdconf((struct fdc_softc *) fd->sc_dv.dv_parent);
1800 		return (0);
1801 	case _IO('f', 102):
1802 		{
1803 		int i;
1804 		struct fdc_softc *fdc = (struct fdc_softc *)
1805 					fd->sc_dv.dv_parent;
1806 		out_fdc(fdc, NE7CMD_SENSEI);
1807 		fdcresult(fdc);
1808 		printf("sensei(%d regs): <", fdc->sc_nstat);
1809 		for (i=0; i< fdc->sc_nstat; i++)
1810 			printf(" 0x%x", fdc->sc_status[i]);
1811 		}
1812 		printf(">\n");
1813 		return (0);
1814 #endif
1815 	default:
1816 		return (ENOTTY);
1817 	}
1818 
1819 #ifdef DIAGNOSTIC
1820 	panic("fdioctl: impossible");
1821 #endif
1822 }
1823 
1824 int
1825 fdformat(dev, finfo, p)
1826 	dev_t dev;
1827 	struct ne7_fd_formb *finfo;
1828 	struct proc *p;
1829 {
1830 	int rv = 0, s;
1831 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1832 	struct fd_type *type = fd->sc_type;
1833 	struct buf *bp;
1834 
1835 	/* set up a buffer header for fdstrategy() */
1836 	bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1837 	if (bp == 0)
1838 		return (ENOBUFS);
1839 
1840 	memset((void *)bp, 0, sizeof(struct buf));
1841 	bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1842 	bp->b_proc = p;
1843 	bp->b_dev = dev;
1844 
1845 	/*
1846 	 * Calculate a fake blkno, so fdstrategy() would initiate a
1847 	 * seek to the requested cylinder.
1848 	 */
1849 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1850 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1851 
1852 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1853 	bp->b_data = (caddr_t)finfo;
1854 
1855 #ifdef FD_DEBUG
1856 	if (fdc_debug)
1857 		printf("fdformat: blkno %x count %ld\n",
1858 			bp->b_blkno, bp->b_bcount);
1859 #endif
1860 
1861 	/* now do the format */
1862 	fdstrategy(bp);
1863 
1864 	/* ...and wait for it to complete */
1865 	s = splbio();
1866 	while (!(bp->b_flags & B_DONE)) {
1867 		rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1868 		if (rv == EWOULDBLOCK)
1869 			break;
1870 	}
1871 	splx(s);
1872 
1873 	if (rv == EWOULDBLOCK) {
1874 		/* timed out */
1875 		rv = EIO;
1876 		biodone(bp);
1877 	}
1878 	if (bp->b_flags & B_ERROR) {
1879 		rv = bp->b_error;
1880 	}
1881 	free(bp, M_TEMP);
1882 	return (rv);
1883 }
1884 
1885 void
1886 fdgetdisklabel(dev)
1887 	dev_t dev;
1888 {
1889 	int unit = FDUNIT(dev), i;
1890 	struct fd_softc *fd = fd_cd.cd_devs[unit];
1891 	struct disklabel *lp = fd->sc_dk.dk_label;
1892 	struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel;
1893 
1894 	memset(lp, 0, sizeof(struct disklabel));
1895 	memset(lp, 0, sizeof(struct cpu_disklabel));
1896 
1897 	lp->d_type = DTYPE_FLOPPY;
1898 	lp->d_secsize = FDC_BSIZE;
1899 	lp->d_secpercyl = fd->sc_type->seccyl;
1900 	lp->d_nsectors = fd->sc_type->sectrac;
1901 	lp->d_ncylinders = fd->sc_type->tracks;
1902 	lp->d_ntracks = fd->sc_type->heads;	/* Go figure... */
1903 	lp->d_rpm = 3600;	/* XXX like it matters... */
1904 
1905 	strncpy(lp->d_typename, "floppy", sizeof(lp->d_typename));
1906 	strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
1907 	lp->d_interleave = 1;
1908 
1909 	lp->d_partitions[RAW_PART].p_offset = 0;
1910 	lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders;
1911 	lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
1912 	lp->d_npartitions = RAW_PART + 1;
1913 
1914 	lp->d_magic = DISKMAGIC;
1915 	lp->d_magic2 = DISKMAGIC;
1916 	lp->d_checksum = dkcksum(lp);
1917 
1918 	/*
1919 	 * Call the generic disklabel extraction routine.  If there's
1920 	 * not a label there, fake it.
1921 	 */
1922 	if (readdisklabel(dev, fdstrategy, lp, clp) != NULL) {
1923 		strncpy(lp->d_packname, "default label",
1924 		    sizeof(lp->d_packname));
1925 		/*
1926 		 * Reset the partition info; it might have gotten
1927 		 * trashed in readdisklabel().
1928 		 *
1929 		 * XXX Why do we have to do this?  readdisklabel()
1930 		 * should be safe...
1931 		 */
1932 		for (i = 0; i < MAXPARTITIONS; ++i) {
1933 			lp->d_partitions[i].p_offset = 0;
1934 			if (i == RAW_PART) {
1935 				lp->d_partitions[i].p_size =
1936 				    lp->d_secpercyl * lp->d_ncylinders;
1937 				lp->d_partitions[i].p_fstype = FS_BSDFFS;
1938 			} else {
1939 				lp->d_partitions[i].p_size = 0;
1940 				lp->d_partitions[i].p_fstype = FS_UNUSED;
1941 			}
1942 		}
1943 		lp->d_npartitions = RAW_PART + 1;
1944 	}
1945 }
1946 
1947 void
1948 fd_do_eject(fdc, unit)
1949 	struct fdc_softc *fdc;
1950 	int unit;
1951 {
1952 	fdc->sc_fcr |= FCR_DSEL(unit)|FCR_EJECT;
1953 	FCR_REG_SYNC();
1954 	delay(10);
1955 	fdc->sc_fcr &= ~(FCR_DSEL(unit)|FCR_EJECT);
1956 	FCR_REG_SYNC();
1957 }
1958 
1959 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet
1960 int	fd_read_md_image __P((size_t *, caddr_t *));
1961 #endif
1962 
1963 /* ARGSUSED */
1964 void
1965 fd_mountroot_hook(dev)
1966 	struct device *dev;
1967 {
1968 	int c;
1969 
1970 	fd_do_eject(fdc_cd.cd_devs[0], 0); /* XXX - doesn't check ``dev'' */
1971 	printf("Insert filesystem floppy and press return.");
1972 	for (;;) {
1973 		c = cngetc();
1974 		if ((c == '\r') || (c == '\n')) {
1975 			printf("\n");
1976 			break;
1977 		}
1978 	}
1979 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet
1980 	{
1981 	extern int (*md_read_image) __P((size_t *, caddr_t *));
1982 	md_read_image = fd_read_md_image;
1983 	}
1984 #endif
1985 }
1986 
1987 #ifdef MEMORY_DISK_HOOKS_sun3x_not_yet
1988 
1989 #define FDMICROROOTSIZE ((2*18*80) << DEV_BSHIFT)
1990 
1991 int
1992 fd_read_md_image(sizep, addrp)
1993 	size_t	*sizep;
1994 	caddr_t	*addrp;
1995 {
1996 	struct buf buf, *bp = &buf;
1997 	dev_t dev;
1998 	off_t offset;
1999 	caddr_t addr;
2000 
2001 	dev = makedev(54,0);	/* XXX */
2002 
2003 	MALLOC(addr, caddr_t, FDMICROROOTSIZE, M_DEVBUF, M_WAITOK);
2004 	*addrp = addr;
2005 
2006 	if (fdopen(dev, 0, S_IFCHR, NULL))
2007 		panic("fd: mountroot: fdopen");
2008 
2009 	offset = 0;
2010 
2011 	for (;;) {
2012 		bp->b_dev = dev;
2013 		bp->b_error = 0;
2014 		bp->b_resid = 0;
2015 		bp->b_proc = NULL;
2016 		bp->b_flags = B_BUSY | B_PHYS | B_RAW | B_READ;
2017 		bp->b_blkno = btodb(offset);
2018 		bp->b_bcount = DEV_BSIZE;
2019 		bp->b_data = addr;
2020 		fdstrategy(bp);
2021 		while ((bp->b_flags & B_DONE) == 0) {
2022 			tsleep((caddr_t)bp, PRIBIO + 1, "physio", 0);
2023 		}
2024 		if (bp->b_error)
2025 			panic("fd: mountroot: fdread error %d", bp->b_error);
2026 
2027 		if (bp->b_resid != 0)
2028 			break;
2029 
2030 		addr += DEV_BSIZE;
2031 		offset += DEV_BSIZE;
2032 		if (offset + DEV_BSIZE > FDMICROROOTSIZE)
2033 			break;
2034 	}
2035 	(void)fdclose(dev, 0, S_IFCHR, NULL);
2036 	*sizep = offset;
2037 	fd_do_eject(fdc_cd.cd_devs[0], FDUNIT(dev)); /* XXX */
2038 	return (0);
2039 }
2040 #endif
2041