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