xref: /netbsd/sys/arch/acorn32/mainbus/fd.c (revision bf9ec67e)
1 /*	$NetBSD: fd.c,v 1.4 2001/12/20 01:20:21 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Charles M. Hannum.
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. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*-
40  * Copyright (c) 1990 The Regents of the University of California.
41  * All rights reserved.
42  *
43  * This code is derived from software contributed to Berkeley by
44  * Don Ahn.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *	This product includes software developed by the University of
57  *	California, Berkeley and its contributors.
58  * 4. Neither the name of the University nor the names of its contributors
59  *    may be used to endorse or promote products derived from this software
60  *    without specific prior written permission.
61  *
62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72  * SUCH DAMAGE.
73  *
74  *	@(#)fd.c	7.4 (Berkeley) 5/25/91
75  *	from: fd.c,v 1.104 1997/01/09 04:30:08 mycroft Exp
76  */
77 
78 /*
79  * Floppy formatting facilities merged from FreeBSD fd.c driver:
80  *	Id: fd.c,v 1.53 1995/03/12 22:40:56 joerg Exp
81  * which carries the same copyright/redistribution notice as shown above with
82  * the addition of the following statement before the "Redistribution and
83  * use ..." clause:
84  *
85  * Copyright (c) 1993, 1994 by
86  *  jc@irbs.UUCP (John Capo)
87  *  vak@zebub.msk.su (Serge Vakulenko)
88  *  ache@astral.msk.su (Andrew A. Chernov)
89  *
90  * Copyright (c) 1993, 1994, 1995 by
91  *  joerg_wunsch@uriah.sax.de (Joerg Wunsch)
92  *  dufault@hda.com (Peter Dufault)
93  */
94 
95 #include "opt_ddb.h"
96 
97 #include <sys/param.h>
98 #include <sys/systm.h>
99 #include <sys/callout.h>
100 #include <sys/kernel.h>
101 #include <sys/file.h>
102 #include <sys/ioctl.h>
103 #include <sys/device.h>
104 #include <sys/disklabel.h>
105 #include <sys/dkstat.h>
106 #include <sys/disk.h>
107 #include <sys/buf.h>
108 #include <sys/malloc.h>
109 #include <sys/uio.h>
110 #include <sys/syslog.h>
111 #include <sys/queue.h>
112 #include <sys/proc.h>
113 #include <sys/fdio.h>
114 
115 #include <uvm/uvm_extern.h>
116 
117 #include <arm/fiq.h>
118 
119 #include <machine/cpu.h>
120 #include <machine/intr.h>
121 #include <machine/conf.h>
122 #include <machine/io.h>
123 #include <arm/arm32/katelib.h>
124 #include <machine/bus.h>
125 
126 #include <arm/iomd/iomdreg.h>
127 #include <arm/iomd/iomdvar.h>
128 
129 #include <acorn32/mainbus/piocvar.h>
130 #include <acorn32/mainbus/fdreg.h>
131 
132 #include "locators.h"
133 
134 #define NE7CMD_CONFIGURE 0x13
135 
136 #define FDUNIT(dev)	(minor(dev) / 8)
137 #define FDTYPE(dev)	(minor(dev) % 8)
138 
139 /* XXX misuse a flag to identify format operation */
140 #define B_FORMAT B_XXX
141 
142 enum fdc_state {
143 	DEVIDLE = 0,
144 	MOTORWAIT,
145 	DOSEEK,
146 	SEEKWAIT,
147 	SEEKTIMEDOUT,
148 	SEEKCOMPLETE,
149 	DOIO,
150 	IOCOMPLETE,
151 	IOTIMEDOUT,
152 	DORESET,
153 	RESETCOMPLETE,
154 	RESETTIMEDOUT,
155 	DORECAL,
156 	RECALWAIT,
157 	RECALTIMEDOUT,
158 	RECALCOMPLETE,
159 };
160 
161 /* software state, per controller */
162 struct fdc_softc {
163 	struct device sc_dev;		/* boilerplate */
164 	void *sc_ih;
165 
166 	bus_space_tag_t sc_iot;		/* ISA i/o space identifier */
167 	bus_space_handle_t   sc_ioh;	/* ISA io handle */
168 
169 	struct callout sc_timo_ch;	/* timeout callout */
170 	struct callout sc_intr_ch;	/* pseudo-intr callout */
171 
172 	/* ...for pseudo-DMA... */
173 	struct fiqhandler sc_fh;	/* FIQ handler descriptor */
174 	struct fiqregs sc_fr;		/* FIQ handler reg context */
175 	int sc_drq;
176 
177 	struct fd_softc *sc_fd[4];	/* pointers to children */
178 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
179 	enum fdc_state sc_state;
180 	int sc_errors;			/* number of retries so far */
181 	u_char sc_status[7];		/* copy of registers */
182 };
183 
184 /* controller driver configuration */
185 int fdcprobe __P((struct device *, struct cfdata *, void *));
186 int fdprint __P((void *, const char *));
187 void fdcattach __P((struct device *, struct device *, void *));
188 
189 struct cfattach fdc_ca = {
190 	sizeof(struct fdc_softc), fdcprobe, fdcattach
191 };
192 
193 /*
194  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
195  * we tell them apart.
196  */
197 struct fd_type {
198 	int	sectrac;	/* sectors per track */
199 	int	heads;		/* number of heads */
200 	int	seccyl;		/* sectors per cylinder */
201 	int	secsize;	/* size code for sectors */
202 	int	datalen;	/* data len when secsize = 0 */
203 	int	steprate;	/* step rate and head unload time */
204 	int	gap1;		/* gap len between sectors */
205 	int	gap2;		/* formatting gap */
206 	int	cyls;		/* total num of cylinders */
207 	int	size;		/* size of disk in sectors */
208 	int	step;		/* steps per cylinder */
209 	int	rate;		/* transfer speed code */
210 	u_char	fillbyte;	/* format fill byte */
211 	u_char	interleave;	/* interleave factor (formatting) */
212 	char	*name;
213 };
214 
215 /* The order of entries in the following table is important -- BEWARE! */
216 struct fd_type fd_types[] = {
217 	{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB"    }, /* 1.44MB diskette */
218 	{ 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB"    }, /* 1.2 MB AT-diskettes */
219 	{  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
220 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
221 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB"    }, /* 3.5" 720kB diskette */
222 	{  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x"  }, /* 720kB in 1.2MB drive */
223 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x"  }, /* 360kB in 720kB drive */
224 };
225 
226 /* software state, per disk (with up to 4 disks per ctlr) */
227 struct fd_softc {
228 	struct device sc_dev;
229 	struct disk sc_dk;
230 
231 	struct fd_type *sc_deftype;	/* default type descriptor */
232 	struct fd_type *sc_type;	/* current type descriptor */
233 	struct fd_type sc_type_copy;	/* copy for fiddling when formatting */
234 
235 	struct callout sc_motoron_ch;
236 	struct callout sc_motoroff_ch;
237 
238 	daddr_t	sc_blkno;	/* starting block number */
239 	int sc_bcount;		/* byte count left */
240  	int sc_opts;			/* user-set options */
241 	int sc_skip;		/* bytes already transferred */
242 	int sc_nblks;		/* number of blocks currently transferring */
243 	int sc_nbytes;		/* number of bytes currently transferring */
244 
245 	int sc_drive;		/* physical unit number */
246 	int sc_flags;
247 #define	FD_OPEN		0x01		/* it's open */
248 #define	FD_MOTOR	0x02		/* motor should be on */
249 #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
250 	int sc_cylin;		/* where we think the head is */
251 
252 	void *sc_sdhook;	/* saved shutdown hook for drive. */
253 
254 	TAILQ_ENTRY(fd_softc) sc_drivechain;
255 	int sc_ops;		/* I/O ops since last switch */
256 	struct buf_queue sc_q;	/* pending I/O requests */
257 	int sc_active;		/* number of active I/O operations */
258 };
259 
260 /* floppy driver configuration */
261 int fdprobe __P((struct device *, struct cfdata *, void *));
262 void fdattach __P((struct device *, struct device *, void *));
263 
264 extern char floppy_read_fiq[], floppy_read_fiq_end[];
265 extern char floppy_write_fiq[], floppy_write_fiq_end[];
266 
267 struct cfattach fd_ca = {
268 	sizeof(struct fd_softc), fdprobe, fdattach
269 };
270 
271 extern struct cfdriver fd_cd;
272 
273 void fdgetdisklabel __P((struct fd_softc *));
274 int fd_get_parms __P((struct fd_softc *));
275 void fdstrategy __P((struct buf *));
276 void fdstart __P((struct fd_softc *));
277 
278 struct dkdriver fddkdriver = { fdstrategy };
279 
280 struct fd_type *fd_nvtotype __P((char *, int, int));
281 void fd_set_motor __P((struct fdc_softc *fdc, int reset));
282 void fd_motor_off __P((void *arg));
283 void fd_motor_on __P((void *arg));
284 int fdcresult __P((struct fdc_softc *fdc));
285 int out_fdc __P((bus_space_tag_t iot, bus_space_handle_t ioh, u_char x));
286 void fdcstart __P((struct fdc_softc *fdc));
287 void fdcstatus __P((struct device *dv, int n, char *s));
288 void fdctimeout __P((void *arg));
289 void fdcpseudointr __P((void *arg));
290 int fdcintr __P((void *));
291 void fdcretry __P((struct fdc_softc *fdc));
292 void fdfinish __P((struct fd_softc *fd, struct buf *bp));
293 __inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t));
294 int fdformat __P((dev_t, struct ne7_fd_formb *, struct proc *));
295 
296 int
297 fdcprobe(parent, cf, aux)
298 	struct device *parent;
299 	struct cfdata *cf;
300 	void *aux;
301 {
302 	struct pioc_attach_args *pa = aux;
303 	bus_space_tag_t iot;
304 	bus_space_handle_t ioh;
305 	int rv;
306 
307 	if (pa->pa_name && strcmp(pa->pa_name, "fdc") != 0)
308 		return(0);
309 
310 	iot = pa->pa_iot;
311 	rv = 0;
312 
313 	/* Map the i/o space. */
314 	if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
315 		return 0;
316 
317 	/* reset */
318 	bus_space_write_2(iot, ioh, fdout, 0);
319 	delay(100);
320 	bus_space_write_2(iot, ioh, fdout, FDO_FRST);
321 
322 	/* see if it can handle a command */
323 	if (out_fdc(iot, ioh, NE7CMD_SPECIFY) < 0)
324 		goto out;
325 	out_fdc(iot, ioh, 0xdf);
326 	out_fdc(iot, ioh, 2);
327 
328 	rv = 1;
329 	pa->pa_iosize = FDC_NPORT;
330 
331  out:
332 	bus_space_unmap(iot, ioh, FDC_NPORT);
333 	return rv;
334 }
335 
336 /*
337  * Arguments passed between fdcattach and fdprobe.
338  */
339 struct fdc_attach_args {
340 	int fa_drive;
341 	struct fd_type *fa_deftype;
342 };
343 
344 /*
345  * Print the location of a disk drive (called just before attaching the
346  * the drive).  If `fdc' is not NULL, the drive was found but was not
347  * in the system config file; print the drive name as well.
348  * Return QUIET (config_find ignores this if the device was configured) to
349  * avoid printing `fdN not configured' messages.
350  */
351 int
352 fdprint(aux, fdc)
353 	void *aux;
354 	const char *fdc;
355 {
356 	register struct fdc_attach_args *fa = aux;
357 
358 	if (!fdc)
359 		printf(" drive %d", fa->fa_drive);
360 	return QUIET;
361 }
362 
363 void
364 fdcattach(parent, self, aux)
365 	struct device *parent, *self;
366 	void *aux;
367 {
368 	struct fdc_softc *fdc = (void *)self;
369 	bus_space_tag_t iot;
370 	bus_space_handle_t ioh;
371 	struct pioc_attach_args *pa = aux;
372 	struct fdc_attach_args fa;
373 	int type;
374 
375 	iot = pa->pa_iot;
376 
377 	/* Re-map the I/O space. */
378 	if (bus_space_map(iot, pa->pa_iobase + pa->pa_offset, FDC_NPORT, 0, &ioh))
379 		panic("fdcattach: couldn't map I/O ports");
380 
381 	fdc->sc_iot = iot;
382 	fdc->sc_ioh = ioh;
383 
384 	fdc->sc_drq = pa->pa_iobase + pa->pa_offset + pa->pa_drq;
385 	fdc->sc_state = DEVIDLE;
386 	TAILQ_INIT(&fdc->sc_drives);
387 
388 	printf("\n");
389 
390 	callout_init(&fdc->sc_timo_ch);
391 	callout_init(&fdc->sc_intr_ch);
392 
393 	fdc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "fdc",
394 	    fdcintr, fdc);
395 	if (!fdc->sc_ih)
396 		panic("%s: Cannot claim IRQ %d\n", self->dv_xname, pa->pa_irq);
397 
398 #if 0
399 	/*
400 	 * The NVRAM info only tells us about the first two disks on the
401 	 * `primary' floppy controller.
402 	 */
403 	if (fdc->sc_dev.dv_unit == 0)
404 		type = mc146818_read(NULL, NVRAM_DISKETTE); /* XXX softc */
405 	else
406 		type = -1;
407 #endif
408 	type = 0x10;	/* XXX - hardcoded for 1 floppy */
409 
410 	/* physical limit: four drives per controller. */
411 	for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) {
412 		if (type >= 0 && fa.fa_drive < 2)
413 			fa.fa_deftype = fd_nvtotype(fdc->sc_dev.dv_xname,
414 			    type, fa.fa_drive);
415 		else
416 			fa.fa_deftype = NULL;		/* unknown */
417 		(void)config_found(self, (void *)&fa, fdprint);
418 	}
419 }
420 
421 int
422 fdprobe(parent, cf, aux)
423 	struct device *parent;
424 	struct cfdata *cf;
425 	void *aux;
426 {
427 	struct fdc_softc *fdc = (void *)parent;
428 	struct fdc_attach_args *fa = aux;
429 	int drive = fa->fa_drive;
430 	bus_space_tag_t iot = fdc->sc_iot;
431 	bus_space_handle_t ioh = fdc->sc_ioh;
432 	int n;
433 
434 	if (cf->cf_loc[FDCCF_DRIVE] != FDCCF_DRIVE_DEFAULT
435 	  && cf->cf_loc[FDCCF_DRIVE] != drive)
436 		return 0;
437 	/*
438 	 * XXX
439 	 * This is to work around some odd interactions between this driver
440 	 * and SMC Ethernet cards.
441 	 */
442 
443 	/* Don't need this for arm32 port but leave for the time being (it won't hurt) */
444 
445 	if (cf->cf_loc[FDCCF_DRIVE] == FDCCF_DRIVE_DEFAULT && drive >= 2)
446 		return 0;
447 
448 	/* select drive and turn on motor */
449 	bus_space_write_2(iot, ioh, fdout, drive | FDO_FRST | FDO_MOEN(drive));
450 	/* wait for motor to spin up */
451 	delay(250000);
452 	out_fdc(iot, ioh, NE7CMD_RECAL);
453 	out_fdc(iot, ioh, drive);
454 	/* wait for recalibrate */
455 	delay(2000000);
456 	out_fdc(iot, ioh, NE7CMD_SENSEI);
457 	n = fdcresult(fdc);
458 #ifdef FD_DEBUG
459 	{
460 		int i;
461 		printf("fdprobe: status");
462 		for (i = 0; i < n; i++)
463 			printf(" %x", fdc->sc_status[i]);
464 		printf("\n");
465 	}
466 #endif
467 	/* turn off motor */
468 	bus_space_write_1(iot, ioh, fdout, FDO_FRST);
469 
470 	if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20)
471 		return 0;
472 
473 	return 1;
474 }
475 
476 /*
477  * Controller is working, and drive responded.  Attach it.
478  */
479 void
480 fdattach(parent, self, aux)
481 	struct device *parent, *self;
482 	void *aux;
483 {
484 	struct fdc_softc *fdc = (void *)parent;
485 	struct fd_softc *fd = (void *)self;
486 	struct fdc_attach_args *fa = aux;
487 	struct fd_type *type = fa->fa_deftype;
488 	int drive = fa->fa_drive;
489 
490 	callout_init(&fd->sc_motoron_ch);
491 	callout_init(&fd->sc_motoroff_ch);
492 
493 	/* XXX Allow `flags' to override device type? */
494 
495 	if (type)
496 		printf(": %s %d cyl, %d head, %d sec\n", type->name,
497 		    type->cyls, type->heads, type->sectrac);
498 	else
499 		printf(": density unknown\n");
500 
501 	BUFQ_INIT(&fd->sc_q);
502 	fd->sc_cylin = -1;
503 	fd->sc_drive = drive;
504 	fd->sc_deftype = type;
505 	fdc->sc_fd[drive] = fd;
506 
507 	/*
508 	 * Initialize and attach the disk structure.
509 	 */
510 	fd->sc_dk.dk_name = fd->sc_dev.dv_xname;
511 	fd->sc_dk.dk_driver = &fddkdriver;
512 	disk_attach(&fd->sc_dk);
513 
514 	/* Needed to power off if the motor is on when we halt. */
515 
516 }
517 
518 /*
519  * Translate nvram type into internal data structure.  Return NULL for
520  * none/unknown/unusable.
521  */
522 struct fd_type *
523 fd_nvtotype(fdc, nvraminfo, drive)
524 	char *fdc;
525 	int nvraminfo, drive;
526 {
527 	int type;
528 
529 	type = (drive == 0 ? nvraminfo : nvraminfo << 4) & 0xf0;
530 	switch (type) {
531 #ifndef RC7500
532 	case 0x00 :
533 		return NULL;
534 #else
535 	case 0x00 :
536 #endif	/* !RC7500 */
537 	case 0x10 :
538 		return &fd_types[0];
539 	default:
540 		printf("%s: drive %d: unknown device type 0x%x\n",
541 		    fdc, drive, type);
542 		return NULL;
543 	}
544 }
545 
546 __inline struct fd_type *
547 fd_dev_to_type(fd, dev)
548 	struct fd_softc *fd;
549 	dev_t dev;
550 {
551 	int type = FDTYPE(dev);
552 
553 	if (type > (sizeof(fd_types) / sizeof(fd_types[0])))
554 		return NULL;
555 	return type ? &fd_types[type - 1] : fd->sc_deftype;
556 }
557 
558 void
559 fdstrategy(bp)
560 	register struct buf *bp;	/* IO operation to perform */
561 {
562 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(bp->b_dev)];
563 	int sz;
564  	int s;
565 
566 	/* Valid unit, controller, and request? */
567 	if (bp->b_blkno < 0 ||
568 	    ((bp->b_bcount % FDC_BSIZE) != 0 &&
569 	     (bp->b_flags & B_FORMAT) == 0)) {
570 		bp->b_error = EINVAL;
571 		goto bad;
572 	}
573 
574 	/* If it's a null transfer, return immediately. */
575 	if (bp->b_bcount == 0)
576 		goto done;
577 
578 	sz = howmany(bp->b_bcount, FDC_BSIZE);
579 
580 	if (bp->b_blkno + sz > fd->sc_type->size) {
581 		sz = fd->sc_type->size - bp->b_blkno;
582 		if (sz == 0) {
583 			/* If exactly at end of disk, return EOF. */
584 			goto done;
585 		}
586 		if (sz < 0) {
587 			/* If past end of disk, return EINVAL. */
588 			bp->b_error = EINVAL;
589 			goto bad;
590 		}
591 		/* Otherwise, truncate request. */
592 		bp->b_bcount = sz << DEV_BSHIFT;
593 	}
594 
595 	bp->b_rawblkno = bp->b_blkno;
596  	bp->b_cylinder = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE) / fd->sc_type->seccyl;
597 
598 #ifdef FD_DEBUG
599 	printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d sz %d\n",
600 	    bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylinder, sz);
601 #endif
602 
603 	/* Queue transfer on drive, activate drive and controller if idle. */
604 	s = splbio();
605 	disksort_cylinder(&fd->sc_q, bp);
606 	callout_stop(&fd->sc_motoroff_ch);		/* a good idea */
607 	if (fd->sc_active == 0)
608 		fdstart(fd);
609 #ifdef DIAGNOSTIC
610 	else {
611 		struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
612 		if (fdc->sc_state == DEVIDLE) {
613 			printf("fdstrategy: controller inactive\n");
614 			fdcstart(fdc);
615 		}
616 	}
617 #endif
618 	splx(s);
619 	return;
620 
621 bad:
622 	bp->b_flags |= B_ERROR;
623 done:
624 	/* Toss transfer; we're done early. */
625 	bp->b_resid = bp->b_bcount;
626 	biodone(bp);
627 }
628 
629 void
630 fdstart(fd)
631 	struct fd_softc *fd;
632 {
633 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
634 	int active = fdc->sc_drives.tqh_first != 0;
635 
636 	/* Link into controller queue. */
637 	fd->sc_active = 1;
638 	TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
639 
640 	/* If controller not already active, start it. */
641 	if (!active)
642 		fdcstart(fdc);
643 }
644 
645 void
646 fdfinish(fd, bp)
647 	struct fd_softc *fd;
648 	struct buf *bp;
649 {
650 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
651 
652 	/*
653 	 * Move this drive to the end of the queue to give others a `fair'
654 	 * chance.  We only force a switch if N operations are completed while
655 	 * another drive is waiting to be serviced, since there is a long motor
656 	 * startup delay whenever we switch.
657 	 */
658 	if (fd->sc_drivechain.tqe_next && ++fd->sc_ops >= 8) {
659 		fd->sc_ops = 0;
660 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
661 		if (BUFQ_NEXT(bp) != NULL)
662 			TAILQ_INSERT_TAIL(&fdc->sc_drives, fd, sc_drivechain);
663 		else
664 			fd->sc_active = 0;
665 	}
666 	bp->b_resid = fd->sc_bcount;
667 	fd->sc_skip = 0;
668 	BUFQ_REMOVE(&fd->sc_q, bp);
669 
670 	biodone(bp);
671 	/* turn off motor 5s from now */
672 	callout_reset(&fd->sc_motoroff_ch, 5 * hz, fd_motor_off, fd);
673 	fdc->sc_state = DEVIDLE;
674 }
675 
676 int
677 fdread(dev, uio, flags)
678 	dev_t dev;
679 	struct uio *uio;
680 	int flags;
681 {
682 
683 	return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio));
684 }
685 
686 int
687 fdwrite(dev, uio, flags)
688 	dev_t dev;
689 	struct uio *uio;
690 	int flags;
691 {
692 
693 	return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio));
694 }
695 
696 void
697 fd_set_motor(fdc, reset)
698 	struct fdc_softc *fdc;
699 	int reset;
700 {
701 	struct fd_softc *fd;
702 	u_char status;
703 	int n;
704 
705 	if ((fd = fdc->sc_drives.tqh_first) != NULL)
706 		status = fd->sc_drive;
707 	else
708 		status = 0;
709 	if (!reset)
710 		status |= FDO_FRST | FDO_FDMAEN;
711 	for (n = 0; n < 4; n++)
712 		if ((fd = fdc->sc_fd[n]) && (fd->sc_flags & FD_MOTOR))
713 			status |= FDO_MOEN(n);
714 	bus_space_write_2(fdc->sc_iot, fdc->sc_ioh, fdout, status);
715 }
716 
717 void
718 fd_motor_off(arg)
719 	void *arg;
720 {
721 	struct fd_softc *fd = arg;
722 	int s;
723 
724 	s = splbio();
725 	fd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
726 	fd_set_motor((struct fdc_softc *)fd->sc_dev.dv_parent, 0);
727 	splx(s);
728 }
729 
730 void
731 fd_motor_on(arg)
732 	void *arg;
733 {
734 	struct fd_softc *fd = arg;
735 	struct fdc_softc *fdc = (void *)fd->sc_dev.dv_parent;
736 	int s;
737 
738 	s = splbio();
739 	fd->sc_flags &= ~FD_MOTOR_WAIT;
740 	if ((fdc->sc_drives.tqh_first == fd) && (fdc->sc_state == MOTORWAIT))
741 		(void) fdcintr(fdc);
742 	splx(s);
743 }
744 
745 int
746 fdcresult(fdc)
747 	struct fdc_softc *fdc;
748 {
749 	bus_space_tag_t iot = fdc->sc_iot;
750 	bus_space_handle_t ioh = fdc->sc_ioh;
751 	u_char i;
752 	int j = 100000,
753 	    n = 0;
754 
755 	for (; j; j--) {
756 		i = bus_space_read_1(iot, ioh, fdsts) &
757 		    (NE7_DIO | NE7_RQM | NE7_CB);
758 		if (i == NE7_RQM)
759 			return n;
760 		if (i == (NE7_DIO | NE7_RQM | NE7_CB)) {
761 			if (n >= sizeof(fdc->sc_status)) {
762 				log(LOG_ERR, "fdcresult: overrun\n");
763 				return -1;
764 			}
765 			fdc->sc_status[n++] =
766 			    bus_space_read_1(iot, ioh, fddata);
767 		}
768 		delay(10);
769 	}
770 	log(LOG_ERR, "fdcresult: timeout\n");
771 	return -1;
772 }
773 
774 int
775 out_fdc(iot, ioh, x)
776 	bus_space_tag_t iot;
777 	bus_space_handle_t ioh;
778 	u_char x;
779 {
780 	int i = 100000;
781 
782 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_DIO) && i-- > 0);
783 	if (i <= 0)
784 		return -1;
785 	while ((bus_space_read_1(iot, ioh, fdsts) & NE7_RQM) == 0 && i-- > 0);
786 	if (i <= 0)
787 		return -1;
788 	bus_space_write_2(iot, ioh, fddata, x);
789 	return 0;
790 }
791 
792 int
793 fdopen(dev, flags, mode, p)
794 	dev_t dev;
795 	int flags;
796 	int mode;
797 	struct proc *p;
798 {
799  	int unit;
800 	struct fd_softc *fd;
801 	struct fd_type *type;
802 
803 	unit = FDUNIT(dev);
804 	if (unit >= fd_cd.cd_ndevs)
805 		return ENXIO;
806 	fd = fd_cd.cd_devs[unit];
807 	if (fd == 0)
808 		return ENXIO;
809 	type = fd_dev_to_type(fd, dev);
810 	if (type == NULL)
811 		return ENXIO;
812 
813 	if ((fd->sc_flags & FD_OPEN) != 0 &&
814 	    memcmp(fd->sc_type, type, sizeof(*type)))
815 		return EBUSY;
816 
817 	fd->sc_type_copy = *type;
818 	fd->sc_type = &fd->sc_type_copy;
819 	fd->sc_cylin = -1;
820 	fd->sc_flags |= FD_OPEN;
821 
822 	return 0;
823 }
824 
825 int
826 fdclose(dev, flags, mode, p)
827 	dev_t dev;
828 	int flags;
829 	int mode;
830 	struct proc *p;
831 {
832 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
833 
834 	fd->sc_flags &= ~FD_OPEN;
835 	fd->sc_opts &= ~(FDOPT_NORETRY|FDOPT_SILENT);
836 	return 0;
837 }
838 
839 void
840 fdcstart(fdc)
841 	struct fdc_softc *fdc;
842 {
843 
844 #ifdef DIAGNOSTIC
845 	/* only got here if controller's drive queue was inactive; should
846 	   be in idle state */
847 	if (fdc->sc_state != DEVIDLE) {
848 		printf("fdcstart: not idle\n");
849 		return;
850 	}
851 #endif
852 	(void) fdcintr(fdc);
853 }
854 
855 void
856 fdcstatus(dv, n, s)
857 	struct device *dv;
858 	int n;
859 	char *s;
860 {
861 	struct fdc_softc *fdc = (void *)dv->dv_parent;
862 	char bits[64];
863 
864 	if (n == 0) {
865 		out_fdc(fdc->sc_iot, fdc->sc_ioh, NE7CMD_SENSEI);
866 		(void) fdcresult(fdc);
867 		n = 2;
868 	}
869 
870 	printf("%s: %s", dv->dv_xname, s);
871 
872 	switch (n) {
873 	case 0:
874 		printf("\n");
875 		break;
876 	case 2:
877 		printf(" (st0 %s cyl %d)\n",
878 		    bitmask_snprintf(fdc->sc_status[0], NE7_ST0BITS,
879 		    bits, sizeof(bits)), fdc->sc_status[1]);
880 		break;
881 	case 7:
882 		printf(" (st0 %s", bitmask_snprintf(fdc->sc_status[0],
883 		    NE7_ST0BITS, bits, sizeof(bits)));
884 		printf(" st1 %s", bitmask_snprintf(fdc->sc_status[1],
885 		    NE7_ST1BITS, bits, sizeof(bits)));
886 		printf(" st2 %s", bitmask_snprintf(fdc->sc_status[2],
887 		    NE7_ST2BITS, bits, sizeof(bits)));
888 		printf(" cyl %d head %d sec %d)\n",
889 		    fdc->sc_status[3], fdc->sc_status[4], fdc->sc_status[5]);
890 		break;
891 #ifdef DIAGNOSTIC
892 	default:
893 		printf("\nfdcstatus: weird size");
894 		break;
895 #endif
896 	}
897 }
898 
899 void
900 fdctimeout(arg)
901 	void *arg;
902 {
903 	struct fdc_softc *fdc = arg;
904 	struct fd_softc *fd = fdc->sc_drives.tqh_first;
905 	int s;
906 
907 	s = splbio();
908 #ifdef DEBUG
909 	log(LOG_ERR,"fdctimeout: state %d\n", fdc->sc_state);
910 #endif
911 	fdcstatus(&fd->sc_dev, 0, "timeout");
912 
913 	if (BUFQ_FIRST(&fd->sc_q) != NULL)
914 		fdc->sc_state++;
915 	else
916 		fdc->sc_state = DEVIDLE;
917 
918 	(void) fdcintr(fdc);
919 	splx(s);
920 }
921 
922 void
923 fdcpseudointr(arg)
924 	void *arg;
925 {
926 	int s;
927 
928 	/* Just ensure it has the right spl. */
929 	s = splbio();
930 	(void) fdcintr(arg);
931 	splx(s);
932 }
933 
934 int
935 fdcintr(arg)
936 	void *arg;
937 {
938 	struct fdc_softc *fdc = arg;
939 #define	st0	fdc->sc_status[0]
940 #define	cyl	fdc->sc_status[1]
941 	struct fd_softc *fd;
942 	struct buf *bp;
943 	bus_space_tag_t iot = fdc->sc_iot;
944 	bus_space_handle_t ioh = fdc->sc_ioh;
945 	int read, head, sec, i, nblks;
946 	struct fd_type *type;
947 	struct ne7_fd_formb *finfo = NULL;
948 
949 loop:
950 	/* Is there a drive for the controller to do a transfer with? */
951 	fd = fdc->sc_drives.tqh_first;
952 	if (fd == NULL) {
953 		fdc->sc_state = DEVIDLE;
954  		return 1;
955 	}
956 
957 	/* Is there a transfer to this drive?  If not, deactivate drive. */
958 	bp = BUFQ_FIRST(&fd->sc_q);
959 	if (bp == NULL) {
960 		fd->sc_ops = 0;
961 		TAILQ_REMOVE(&fdc->sc_drives, fd, sc_drivechain);
962 		fd->sc_active = 0;
963 		goto loop;
964 	}
965 
966 	if (bp->b_flags & B_FORMAT)
967 		finfo = (struct ne7_fd_formb *)bp->b_data;
968 
969 	switch (fdc->sc_state) {
970 	case DEVIDLE:
971 		fdc->sc_errors = 0;
972 		fd->sc_skip = 0;
973 		fd->sc_bcount = bp->b_bcount;
974 		fd->sc_blkno = bp->b_blkno / (FDC_BSIZE / DEV_BSIZE);
975 		callout_stop(&fd->sc_motoroff_ch);
976 		if ((fd->sc_flags & FD_MOTOR_WAIT) != 0) {
977 			fdc->sc_state = MOTORWAIT;
978 			return 1;
979 		}
980 		if ((fd->sc_flags & FD_MOTOR) == 0) {
981 			/* Turn on the motor, being careful about pairing. */
982 			struct fd_softc *ofd = fdc->sc_fd[fd->sc_drive ^ 1];
983 			if (ofd && ofd->sc_flags & FD_MOTOR) {
984 				callout_stop(&ofd->sc_motoroff_ch);
985 				ofd->sc_flags &= ~(FD_MOTOR | FD_MOTOR_WAIT);
986 			}
987 			fd->sc_flags |= FD_MOTOR | FD_MOTOR_WAIT;
988 			fd_set_motor(fdc, 0);
989 			fdc->sc_state = MOTORWAIT;
990 			/* Allow .25s for motor to stabilize. */
991 			callout_reset(&fd->sc_motoron_ch, hz / 4,
992 			    fd_motor_on, fd);
993 			return 1;
994 		}
995 		/* Make sure the right drive is selected. */
996 		fd_set_motor(fdc, 0);
997 
998 		/* fall through */
999 	case DOSEEK:
1000 	doseek:
1001 		if (fd->sc_cylin == bp->b_cylinder)
1002 			goto doio;
1003 
1004 #if 1
1005 		out_fdc(iot, ioh, NE7CMD_CONFIGURE);/* configure command */
1006 		out_fdc(iot, ioh, 0);
1007 		out_fdc(iot, ioh, 0x18);
1008 		out_fdc(iot, ioh, 0);
1009 #endif
1010 		out_fdc(iot, ioh, NE7CMD_SPECIFY);/* specify command */
1011 		out_fdc(iot, ioh, fd->sc_type->steprate);
1012 		out_fdc(iot, ioh, 6);		/* XXX head load time == 6ms */
1013 
1014 		out_fdc(iot, ioh, NE7CMD_SEEK);	/* seek function */
1015 		out_fdc(iot, ioh, fd->sc_drive);	/* drive number */
1016 		out_fdc(iot, ioh, bp->b_cylinder * fd->sc_type->step);
1017 
1018 		fd->sc_cylin = -1;
1019 		fdc->sc_state = SEEKWAIT;
1020 
1021 		fd->sc_dk.dk_seek++;
1022 		disk_busy(&fd->sc_dk);
1023 
1024 		callout_reset(&fdc->sc_timo_ch, 4 * hz, fdctimeout, fdc);
1025 		return 1;
1026 
1027 	case DOIO:
1028 	doio:
1029 		type = fd->sc_type;
1030 		if (finfo)
1031 			fd->sc_skip = (char *)&(finfo->fd_formb_cylno(0)) -
1032 				      (char *)finfo;
1033 		sec = fd->sc_blkno % type->seccyl;
1034 		nblks = type->seccyl - sec;
1035 		nblks = min(nblks, fd->sc_bcount / FDC_BSIZE);
1036 		nblks = min(nblks, FDC_MAXIOSIZE / FDC_BSIZE);
1037 		fd->sc_nblks = nblks;
1038 		fd->sc_nbytes = finfo ? bp->b_bcount : nblks * FDC_BSIZE;
1039 		head = sec / type->sectrac;
1040 		sec -= head * type->sectrac;
1041 #ifdef DIAGNOSTIC
1042 		{int block;
1043 		 block = (fd->sc_cylin * type->heads + head) * type->sectrac + sec;
1044 		 if (block != fd->sc_blkno) {
1045 			 printf("fdcintr: block %d != blkno %d\n",
1046 				block, fd->sc_blkno);
1047 #ifdef DDB
1048 			 Debugger();
1049 #endif
1050 		 }}
1051 #endif
1052 		read = bp->b_flags & B_READ;
1053 		if (read) {
1054 			fdc->sc_fh.fh_func = floppy_read_fiq;
1055 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
1056 			    floppy_read_fiq;
1057 		} else {
1058 			fdc->sc_fh.fh_func = floppy_write_fiq;
1059 			fdc->sc_fh.fh_size = floppy_read_fiq_end -
1060 			    floppy_read_fiq;
1061 		}
1062 		fdc->sc_fh.fh_flags = 0;
1063 		fdc->sc_fh.fh_regs = &fdc->sc_fr;
1064 		fdc->sc_fr.fr_r9 = IOMD_BASE + (IOMD_FIQRQ << 2);
1065 		fdc->sc_fr.fr_r10 = fd->sc_nbytes;
1066 		fdc->sc_fr.fr_r11 = (u_int)(bp->b_data + fd->sc_skip);
1067 		fdc->sc_fr.fr_r12 = fdc->sc_drq;
1068 #ifdef FD_DEBUG
1069 		printf("fdc-doio:r9=%x r10=%x r11=%x r12=%x data=%x skip=%x\n",
1070 		    fdc->sc_fr.fr_r9, fdc->sc_fr.fh_r10, fdc->sc_fr.fh_r11,
1071 		    fdc->sc_fr.fh_r12, (u_int)bp->b_data, fd->sc_skip);
1072 #endif
1073 		if (fiq_claim(&fdc->sc_fh) == -1)
1074 			panic("%s: Cannot claim FIQ vector\n", fdc->sc_dev.dv_xname);
1075 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
1076 		bus_space_write_2(iot, ioh, fdctl, type->rate);
1077 #ifdef FD_DEBUG
1078 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1079 			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1080 			head, sec, nblks);
1081 #endif
1082 		if (finfo) {
1083 			/* formatting */
1084 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1085 				fdc->sc_errors = 4;
1086 				fdcretry(fdc);
1087 				goto loop;
1088 			}
1089 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1090 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
1091 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1092 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1093 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1094 		} else {
1095 			if (read)
1096 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
1097 			else
1098 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1099 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1100 			out_fdc(iot, ioh, fd->sc_cylin); /* track */
1101 			out_fdc(iot, ioh, head);
1102 			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
1103 			out_fdc(iot, ioh, type->secsize);/* sector size */
1104 			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1105 			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
1106 			out_fdc(iot, ioh, type->datalen);/* data length */
1107 		}
1108 		fdc->sc_state = IOCOMPLETE;
1109 
1110 		disk_busy(&fd->sc_dk);
1111 
1112 		/* allow 2 seconds for operation */
1113 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1114 		return 1;				/* will return later */
1115 
1116 	case SEEKWAIT:
1117 		callout_stop(&fdc->sc_timo_ch);
1118 		fdc->sc_state = SEEKCOMPLETE;
1119 		/* allow 1/50 second for heads to settle */
1120 #if 0
1121 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1122 #endif
1123 		return 1;
1124 
1125 	case SEEKCOMPLETE:
1126 		disk_unbusy(&fd->sc_dk, 0);	/* no data on seek */
1127 
1128 		/* Make sure seek really happened. */
1129 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1130 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1131 		    cyl != bp->b_cylinder * fd->sc_type->step) {
1132 #ifdef FD_DEBUG
1133 			fdcstatus(&fd->sc_dev, 2, "seek failed");
1134 #endif
1135 			fdcretry(fdc);
1136 			goto loop;
1137 		}
1138 		fd->sc_cylin = bp->b_cylinder;
1139 		goto doio;
1140 
1141 	case IOTIMEDOUT:
1142 		fiq_release(&fdc->sc_fh);
1143 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1144 	case SEEKTIMEDOUT:
1145 	case RECALTIMEDOUT:
1146 	case RESETTIMEDOUT:
1147 		fdcretry(fdc);
1148 		goto loop;
1149 
1150 	case IOCOMPLETE: /* IO DONE, post-analyze */
1151 		callout_stop(&fdc->sc_timo_ch);
1152 
1153 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid));
1154 
1155 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1156 			fiq_release(&fdc->sc_fh);
1157 			IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1158 #ifdef FD_DEBUG
1159 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1160 			    "read failed" : "write failed");
1161 			printf("blkno %d nblks %d\n",
1162 			    fd->sc_blkno, fd->sc_nblks);
1163 #endif
1164 			fdcretry(fdc);
1165 			goto loop;
1166 		}
1167 		fiq_release(&fdc->sc_fh);
1168 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1169 		if (fdc->sc_errors) {
1170 #if 0
1171 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1172 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1173 			printf("\n");
1174 #endif
1175 			fdc->sc_errors = 0;
1176 		}
1177 		fd->sc_blkno += fd->sc_nblks;
1178 		fd->sc_skip += fd->sc_nbytes;
1179 		fd->sc_bcount -= fd->sc_nbytes;
1180 		if (!finfo && fd->sc_bcount > 0) {
1181 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1182 			goto doseek;
1183 		}
1184 		fdfinish(fd, bp);
1185 		goto loop;
1186 
1187 	case DORESET:
1188 		/* try a reset, keep motor on */
1189 		fd_set_motor(fdc, 1);
1190 		delay(100);
1191 		fd_set_motor(fdc, 0);
1192 		fdc->sc_state = RESETCOMPLETE;
1193 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1194 		return 1;			/* will return later */
1195 
1196 	case RESETCOMPLETE:
1197 		callout_stop(&fdc->sc_timo_ch);
1198 		/* clear the controller output buffer */
1199 		for (i = 0; i < 4; i++) {
1200 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1201 			(void) fdcresult(fdc);
1202 		}
1203 
1204 		/* fall through */
1205 	case DORECAL:
1206 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
1207 		out_fdc(iot, ioh, fd->sc_drive);
1208 		fdc->sc_state = RECALWAIT;
1209 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1210 		return 1;			/* will return later */
1211 
1212 	case RECALWAIT:
1213 		callout_stop(&fdc->sc_timo_ch);
1214 		fdc->sc_state = RECALCOMPLETE;
1215 		/* allow 1/30 second for heads to settle */
1216 #if 0
1217 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1218 #endif
1219 		return 1;			/* will return later */
1220 
1221 	case RECALCOMPLETE:
1222 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1223 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1224 #ifdef FD_DEBUG
1225 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1226 #endif
1227 			fdcretry(fdc);
1228 			goto loop;
1229 		}
1230 		fd->sc_cylin = 0;
1231 		goto doseek;
1232 
1233 	case MOTORWAIT:
1234 		if (fd->sc_flags & FD_MOTOR_WAIT)
1235 			return 1;		/* time's not up yet */
1236 		goto doseek;
1237 
1238 	default:
1239 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1240 		return 1;
1241 	}
1242 #ifdef DIAGNOSTIC
1243 	panic("fdcintr: impossible");
1244 #endif
1245 #undef	st0
1246 #undef	cyl
1247 }
1248 
1249 void
1250 fdcretry(fdc)
1251 	struct fdc_softc *fdc;
1252 {
1253 	char bits[64];
1254 	struct fd_softc *fd;
1255 	struct buf *bp;
1256 
1257 	fd = fdc->sc_drives.tqh_first;
1258 	bp = BUFQ_FIRST(&fd->sc_q);
1259 
1260 	if (fd->sc_opts & FDOPT_NORETRY)
1261 	    goto fail;
1262 	switch (fdc->sc_errors) {
1263 	case 0:
1264 		/* try again */
1265 		fdc->sc_state = DOSEEK;
1266 		break;
1267 
1268 	case 1: case 2: case 3:
1269 		/* didn't work; try recalibrating */
1270 		fdc->sc_state = DORECAL;
1271 		break;
1272 
1273 	case 4:
1274 		/* still no go; reset the bastard */
1275 		fdc->sc_state = DORESET;
1276 		break;
1277 
1278 	default:
1279 	fail:
1280 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1281 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
1282 				fd->sc_skip / FDC_BSIZE,
1283 				(struct disklabel *)NULL);
1284 
1285 			printf(" (st0 %s",
1286 			       bitmask_snprintf(fdc->sc_status[0],
1287 						NE7_ST0BITS, bits,
1288 						sizeof(bits)));
1289 			printf(" st1 %s",
1290 			       bitmask_snprintf(fdc->sc_status[1],
1291 						NE7_ST1BITS, bits,
1292 						sizeof(bits)));
1293 			printf(" st2 %s",
1294 			       bitmask_snprintf(fdc->sc_status[2],
1295 						NE7_ST2BITS, bits,
1296 						sizeof(bits)));
1297 			printf(" cyl %d head %d sec %d)\n",
1298 			       fdc->sc_status[3],
1299 			       fdc->sc_status[4],
1300 			       fdc->sc_status[5]);
1301 		}
1302 
1303 		bp->b_flags |= B_ERROR;
1304 		bp->b_error = EIO;
1305 		fdfinish(fd, bp);
1306 	}
1307 	fdc->sc_errors++;
1308 }
1309 
1310 int
1311 fdsize(dev)
1312 	dev_t dev;
1313 {
1314 
1315 	/* Swapping to floppies would not make sense. */
1316 	return -1;
1317 }
1318 
1319 int
1320 fddump(dev, blkno, va, size)
1321 	dev_t dev;
1322 	daddr_t blkno;
1323 	caddr_t va;
1324 	size_t size;
1325 {
1326 
1327 	/* Not implemented. */
1328 	return ENXIO;
1329 }
1330 
1331 int
1332 fdioctl(dev, cmd, addr, flag, p)
1333 	dev_t dev;
1334 	u_long cmd;
1335 	caddr_t addr;
1336 	int flag;
1337 	struct proc *p;
1338 {
1339 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1340 	struct fdformat_parms *form_parms;
1341 	struct fdformat_cmd *form_cmd;
1342 	struct ne7_fd_formb *fd_formb;
1343 	struct disklabel buffer;
1344 	int error;
1345 	unsigned int scratch;
1346 	int il[FD_MAX_NSEC + 1];
1347 	register int i, j;
1348 
1349 	switch (cmd) {
1350 	case DIOCGDINFO:
1351 		memset(&buffer, 0, sizeof(buffer));
1352 
1353 		buffer.d_secpercyl = fd->sc_type->seccyl;
1354 		buffer.d_type = DTYPE_FLOPPY;
1355 		buffer.d_secsize = FDC_BSIZE;
1356 
1357 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1358 			return EINVAL;
1359 
1360 		*(struct disklabel *)addr = buffer;
1361 		return 0;
1362 
1363 	case DIOCWLABEL:
1364 		if ((flag & FWRITE) == 0)
1365 			return EBADF;
1366 		/* XXX do something */
1367 		return 0;
1368 
1369 	case DIOCWDINFO:
1370 		if ((flag & FWRITE) == 0)
1371 			return EBADF;
1372 
1373 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1374 		if (error)
1375 			return error;
1376 
1377 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1378 		return error;
1379 
1380 	case FDIOCGETFORMAT:
1381 		form_parms = (struct fdformat_parms *)addr;
1382 		form_parms->fdformat_version = FDFORMAT_VERSION;
1383 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1384 		form_parms->ncyl = fd->sc_type->cyls;
1385 		form_parms->nspt = fd->sc_type->sectrac;
1386 		form_parms->ntrk = fd->sc_type->heads;
1387 		form_parms->stepspercyl = fd->sc_type->step;
1388 		form_parms->gaplen = fd->sc_type->gap2;
1389 		form_parms->fillbyte = fd->sc_type->fillbyte;
1390 		form_parms->interleave = fd->sc_type->interleave;
1391 		switch (fd->sc_type->rate) {
1392 		case FDC_500KBPS:
1393 			form_parms->xfer_rate = 500 * 1024;
1394 			break;
1395 		case FDC_300KBPS:
1396 			form_parms->xfer_rate = 300 * 1024;
1397 			break;
1398 		case FDC_250KBPS:
1399 			form_parms->xfer_rate = 250 * 1024;
1400 			break;
1401 		default:
1402 			return EINVAL;
1403 		}
1404 		return 0;
1405 
1406 	case FDIOCSETFORMAT:
1407 		if((flag & FWRITE) == 0)
1408 			return EBADF;	/* must be opened for writing */
1409 		form_parms = (struct fdformat_parms *)addr;
1410 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
1411 			return EINVAL;	/* wrong version of formatting prog */
1412 
1413 		scratch = form_parms->nbps >> 7;
1414 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1415 		    scratch & ~(1 << (ffs(scratch)-1)))
1416 			/* not a power-of-two multiple of 128 */
1417 			return EINVAL;
1418 
1419 		switch (form_parms->xfer_rate) {
1420 		case 500 * 1024:
1421 			fd->sc_type->rate = FDC_500KBPS;
1422 			break;
1423 		case 300 * 1024:
1424 			fd->sc_type->rate = FDC_300KBPS;
1425 			break;
1426 		case 250 * 1024:
1427 			fd->sc_type->rate = FDC_250KBPS;
1428 			break;
1429 		default:
1430 			return EINVAL;
1431 		}
1432 
1433 		if (form_parms->nspt > FD_MAX_NSEC ||
1434 		    form_parms->fillbyte > 0xff ||
1435 		    form_parms->interleave > 0xff)
1436 			return EINVAL;
1437 		fd->sc_type->sectrac = form_parms->nspt;
1438 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1439 			return EINVAL;
1440 		fd->sc_type->heads = form_parms->ntrk;
1441 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1442 		fd->sc_type->secsize = ffs(scratch)-1;
1443 		fd->sc_type->gap2 = form_parms->gaplen;
1444 		fd->sc_type->cyls = form_parms->ncyl;
1445 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1446 			form_parms->nbps / DEV_BSIZE;
1447 		fd->sc_type->step = form_parms->stepspercyl;
1448 		fd->sc_type->fillbyte = form_parms->fillbyte;
1449 		fd->sc_type->interleave = form_parms->interleave;
1450 		return 0;
1451 
1452 	case FDIOCFORMAT_TRACK:
1453 		if((flag & FWRITE) == 0)
1454 			return EBADF;	/* must be opened for writing */
1455 		form_cmd = (struct fdformat_cmd *)addr;
1456 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1457 			return EINVAL;	/* wrong version of formatting prog */
1458 
1459 		if (form_cmd->head >= fd->sc_type->heads ||
1460 		    form_cmd->cylinder >= fd->sc_type->cyls) {
1461 			return EINVAL;
1462 		}
1463 
1464 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
1465 		    M_TEMP, M_NOWAIT);
1466 		if(fd_formb == 0)
1467 			return ENOMEM;
1468 
1469 
1470 		fd_formb->head = form_cmd->head;
1471 		fd_formb->cyl = form_cmd->cylinder;
1472 		fd_formb->transfer_rate = fd->sc_type->rate;
1473 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1474 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1475 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1476 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1477 
1478 		memset(il, 0, sizeof il);
1479 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1480 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
1481 				j++;
1482 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1483 			j += fd->sc_type->interleave;
1484 		}
1485 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1486 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1487 			fd_formb->fd_formb_headno(i) = form_cmd->head;
1488 			fd_formb->fd_formb_secno(i) = il[i+1];
1489 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1490 		}
1491 
1492 		error = fdformat(dev, fd_formb, p);
1493 		free(fd_formb, M_TEMP);
1494 		return error;
1495 
1496 	case FDIOCGETOPTS:		/* get drive options */
1497 		*(int *)addr = fd->sc_opts;
1498 		return 0;
1499 
1500 	case FDIOCSETOPTS:		/* set drive options */
1501 		fd->sc_opts = *(int *)addr;
1502 		return 0;
1503 
1504 	default:
1505 		return ENOTTY;
1506 	}
1507 
1508 #ifdef DIAGNOSTIC
1509 	panic("fdioctl: impossible");
1510 #endif
1511 }
1512 
1513 int
1514 fdformat(dev, finfo, p)
1515 	dev_t dev;
1516 	struct ne7_fd_formb *finfo;
1517 	struct proc *p;
1518 {
1519 	int rv = 0, s;
1520 	struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)];
1521 	struct fd_type *type = fd->sc_type;
1522 	struct buf *bp;
1523 
1524 	/* set up a buffer header for fdstrategy() */
1525 	bp = (struct buf *)malloc(sizeof(struct buf), M_TEMP, M_NOWAIT);
1526 	if(bp == 0)
1527 		return ENOBUFS;
1528 	memset((void *)bp, 0, sizeof(struct buf));
1529 	bp->b_flags = B_BUSY | B_PHYS | B_FORMAT;
1530 	bp->b_proc = p;
1531 	bp->b_dev = dev;
1532 
1533 	/*
1534 	 * calculate a fake blkno, so fdstrategy() would initiate a
1535 	 * seek to the requested cylinder
1536 	 */
1537 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1538 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1539 
1540 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1541 	bp->b_data = (caddr_t)finfo;
1542 
1543 #ifdef DEBUG
1544 	printf("fdformat: blkno %x count %lx\n", bp->b_blkno, bp->b_bcount);
1545 #endif
1546 
1547 	/* now do the format */
1548 	fdstrategy(bp);
1549 
1550 	/* ...and wait for it to complete */
1551 	s = splbio();
1552 	while(!(bp->b_flags & B_DONE)) {
1553 		rv = tsleep((caddr_t)bp, PRIBIO, "fdform", 20 * hz);
1554 		if (rv == EWOULDBLOCK)
1555 			break;
1556 	}
1557 	splx(s);
1558 
1559 	if (rv == EWOULDBLOCK) {
1560 		/* timed out */
1561 		rv = EIO;
1562 		biodone(bp);
1563 	}
1564 	if(bp->b_flags & B_ERROR) {
1565 		rv = bp->b_error;
1566 	}
1567 	free(bp, M_TEMP);
1568 	return rv;
1569 }
1570 
1571 #include "md.h"
1572 #if NMD > 0
1573 
1574 #include <dev/md.h>
1575 
1576 int load_memory_disc_from_floppy __P((struct md_conf *md, dev_t dev));
1577 
1578 int
1579 load_memory_disc_from_floppy(md, dev)
1580 	struct md_conf *md;
1581 	dev_t dev;
1582 {
1583 	struct buf *bp;
1584 	int loop;
1585 	int s;
1586 	int type;
1587 	int floppysize;
1588 
1589 	if (major(dev) != 17)	/* XXX - nice if the major was defined elsewhere */
1590 		return(EINVAL);
1591 
1592 	if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
1593 		return(EBUSY);
1594 
1595 	type = FDTYPE(dev) - 1;
1596 	if (type < 0) type = 0;
1597 	floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
1598 
1599 	if (md->md_size < floppysize) {
1600 		printf("Memory disc is not big enough for floppy image\n");
1601 		return(EINVAL);
1602 	}
1603 
1604 /* We have the memory disk ! */
1605 
1606 	printf("Loading memory disc : %4dK ", 0);
1607 
1608 /* obtain a buffer */
1609 
1610 	bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
1611 
1612 /* request no partition relocation by driver on I/O operations */
1613 
1614 	bp->b_dev = dev;
1615 
1616 	s = spl0();
1617 
1618 	if (fdopen(bp->b_dev, 0, 0, curproc) != 0) {
1619 		brelse(bp);
1620 		printf("Cannot open floppy device\n");
1621 			return(EINVAL);
1622 	}
1623 
1624 	for (loop = 0;
1625 	    loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
1626 	    ++loop) {
1627 		printf("\x08\x08\x08\x08\x08\x08%4dK ",
1628 		    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1629 		bp->b_blkno = loop * fd_types[type].sectrac;
1630 		bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
1631 		bp->b_flags |= B_READ;
1632 		bp->b_error = 0;
1633 		bp->b_resid = 0;
1634 		fdstrategy(bp);
1635 
1636 		if (biowait(bp))
1637 			panic("Cannot load floppy image\n");
1638 
1639 		memcpy((caddr_t)md->md_addr + loop * fd_types[type].sectrac
1640 		    * DEV_BSIZE, (caddr_t)bp->b_data,
1641 		    fd_types[type].sectrac * DEV_BSIZE);
1642 	}
1643 	printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1644 	    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1645 
1646 	fdclose(bp->b_dev, 0, 0, curproc);
1647 
1648 	brelse(bp);
1649 
1650 	splx(s);
1651 	return(0);
1652 }
1653 
1654 #endif
1655