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