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