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