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