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