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