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