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