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