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