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