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