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