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