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