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