xref: /netbsd/sys/arch/acorn32/mainbus/fd.c (revision 6550d01e)
1 /*	$NetBSD: fd.c,v 1.49 2010/12/09 05:14:28 uebayasi 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.49 2010/12/09 05:14:28 uebayasi Exp $");
86 
87 #include "opt_ddb.h"
88 
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/callout.h>
92 #include <sys/kernel.h>
93 #include <sys/file.h>
94 #include <sys/ioctl.h>
95 #include <sys/device.h>
96 #include <sys/disklabel.h>
97 #include <sys/disk.h>
98 #include <sys/buf.h>
99 #include <sys/bufq.h>
100 #include <sys/malloc.h>
101 #include <sys/uio.h>
102 #include <sys/syslog.h>
103 #include <sys/queue.h>
104 #include <sys/proc.h>
105 #include <sys/fdio.h>
106 #include <sys/conf.h>
107 
108 #include <uvm/uvm_extern.h>
109 
110 #include <arm/fiq.h>
111 
112 #include <machine/cpu.h>
113 #include <machine/intr.h>
114 #include <machine/io.h>
115 #include <arm/arm32/katelib.h>
116 #include <machine/bus.h>
117 
118 #include <arm/iomd/iomdreg.h>
119 #include <arm/iomd/iomdvar.h>
120 
121 #include <acorn32/mainbus/piocvar.h>
122 #include <acorn32/mainbus/fdreg.h>
123 
124 #include "locators.h"
125 
126 #define NE7CMD_CONFIGURE 0x13
127 
128 #define FDUNIT(dev)	(minor(dev) / 8)
129 #define FDTYPE(dev)	(minor(dev) % 8)
130 
131 /* (mis)use device use flag to identify format operation */
132 #define B_FORMAT B_DEVPRIVATE
133 
134 enum fdc_state {
135 	DEVIDLE = 0,
136 	MOTORWAIT,
137 	DOSEEK,
138 	SEEKWAIT,
139 	SEEKTIMEDOUT,
140 	SEEKCOMPLETE,
141 	DOIO,
142 	IOCOMPLETE,
143 	IOTIMEDOUT,
144 	DORESET,
145 	RESETCOMPLETE,
146 	RESETTIMEDOUT,
147 	DORECAL,
148 	RECALWAIT,
149 	RECALTIMEDOUT,
150 	RECALCOMPLETE,
151 };
152 
153 /* software state, per controller */
154 struct fdc_softc {
155 	struct device sc_dev;		/* boilerplate */
156 	void *sc_ih;
157 
158 	bus_space_tag_t sc_iot;		/* ISA i/o space identifier */
159 	bus_space_handle_t   sc_ioh;	/* ISA io handle */
160 
161 	struct callout sc_timo_ch;	/* timeout callout */
162 	struct callout sc_intr_ch;	/* pseudo-intr callout */
163 
164 	/* ...for pseudo-DMA... */
165 	struct fiqhandler sc_fh;	/* FIQ handler descriptor */
166 	struct fiqregs sc_fr;		/* FIQ handler reg context */
167 	int sc_drq;
168 
169 	struct fd_softc *sc_fd[4];	/* pointers to children */
170 	TAILQ_HEAD(drivehead, fd_softc) sc_drives;
171 	enum fdc_state sc_state;
172 	int sc_errors;			/* number of retries so far */
173 	u_char sc_status[7];		/* copy of registers */
174 };
175 
176 /* controller driver configuration */
177 int fdcprobe(struct device *, struct cfdata *, void *);
178 int fdprint(void *, const char *);
179 void fdcattach(struct device *, struct device *, void *);
180 
181 CFATTACH_DECL(fdc, sizeof(struct fdc_softc),
182     fdcprobe, fdcattach, NULL, NULL);
183 
184 /*
185  * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how
186  * we tell them apart.
187  */
188 struct fd_type {
189 	int	sectrac;	/* sectors per track */
190 	int	heads;		/* number of heads */
191 	int	seccyl;		/* sectors per cylinder */
192 	int	secsize;	/* size code for sectors */
193 	int	datalen;	/* data len when secsize = 0 */
194 	int	steprate;	/* step rate and head unload time */
195 	int	gap1;		/* gap len between sectors */
196 	int	gap2;		/* formatting gap */
197 	int	cyls;		/* total num of cylinders */
198 	int	size;		/* size of disk in sectors */
199 	int	step;		/* steps per cylinder */
200 	int	rate;		/* transfer speed code */
201 	u_char	fillbyte;	/* format fill byte */
202 	u_char	interleave;	/* interleave factor (formatting) */
203 	const char *name;
204 };
205 
206 /* The order of entries in the following table is important -- BEWARE! */
207 struct fd_type fd_types[] = {
208 	{ 18,2,36,2,0xff,0xcf,0x1b,0x6c,80,2880,1,FDC_500KBPS,0xf6,1, "1.44MB"    }, /* 1.44MB diskette */
209 	{ 15,2,30,2,0xff,0xdf,0x1b,0x54,80,2400,1,FDC_500KBPS,0xf6,1, "1.2MB"    }, /* 1.2 MB AT-diskettes */
210 	{  9,2,18,2,0xff,0xdf,0x23,0x50,40, 720,2,FDC_300KBPS,0xf6,1, "360KB/AT" }, /* 360kB in 1.2MB drive */
211 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,1,FDC_250KBPS,0xf6,1, "360KB/PC" }, /* 360kB PC diskettes */
212 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,80,1440,1,FDC_250KBPS,0xf6,1, "720KB"    }, /* 3.5" 720kB diskette */
213 	{  9,2,18,2,0xff,0xdf,0x23,0x50,80,1440,1,FDC_300KBPS,0xf6,1, "720KB/x"  }, /* 720kB in 1.2MB drive */
214 	{  9,2,18,2,0xff,0xdf,0x2a,0x50,40, 720,2,FDC_250KBPS,0xf6,1, "360KB/x"  }, /* 360kB in 720kB drive */
215 };
216 
217 /* software state, per disk (with up to 4 disks per ctlr) */
218 struct fd_softc {
219 	struct device sc_dev;
220 	struct disk sc_dk;
221 
222 	struct fd_type *sc_deftype;	/* default type descriptor */
223 	struct fd_type *sc_type;	/* current type descriptor */
224 	struct fd_type sc_type_copy;	/* copy for fiddling when formatting */
225 
226 	struct callout sc_motoron_ch;
227 	struct callout sc_motoroff_ch;
228 
229 	daddr_t	sc_blkno;	/* starting block number */
230 	int sc_bcount;		/* byte count left */
231  	int sc_opts;			/* user-set options */
232 	int sc_skip;		/* bytes already transferred */
233 	int sc_nblks;		/* number of blocks currently transferring */
234 	int sc_nbytes;		/* number of bytes currently transferring */
235 
236 	int sc_drive;		/* physical unit number */
237 	int sc_flags;
238 #define	FD_OPEN		0x01		/* it's open */
239 #define	FD_MOTOR	0x02		/* motor should be on */
240 #define	FD_MOTOR_WAIT	0x04		/* motor coming up */
241 	int sc_cylin;		/* where we think the head is */
242 
243 	void *sc_sdhook;	/* saved shutdown hook for drive. */
244 
245 	TAILQ_ENTRY(fd_softc) sc_drivechain;
246 	int sc_ops;		/* I/O ops since last switch */
247 	struct bufq_state *sc_q;/* pending I/O requests */
248 	int sc_active;		/* number of active I/O operations */
249 };
250 
251 /* floppy driver configuration */
252 int fdprobe(struct device *, struct cfdata *, void *);
253 void fdattach(struct device *, struct device *, void *);
254 
255 extern char floppy_read_fiq[], floppy_read_fiq_end[];
256 extern char floppy_write_fiq[], floppy_write_fiq_end[];
257 
258 CFATTACH_DECL(fd, sizeof(struct fd_softc),
259     fdprobe, fdattach, NULL, NULL);
260 
261 extern struct cfdriver fd_cd;
262 
263 dev_type_open(fdopen);
264 dev_type_close(fdclose);
265 dev_type_read(fdread);
266 dev_type_write(fdwrite);
267 dev_type_ioctl(fdioctl);
268 dev_type_strategy(fdstrategy);
269 
270 const struct bdevsw fd_bdevsw = {
271 	fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
272 };
273 
274 const struct cdevsw fd_cdevsw = {
275 	fdopen, fdclose, fdread, fdwrite, fdioctl,
276 	nostop, notty, nopoll, nommap, nokqfilter, D_DISK
277 };
278 
279 void fdgetdisklabel(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(struct device *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(struct device *parent, struct cfdata *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(struct device *parent, struct device *self, void *aux)
365 {
366 	struct fdc_softc *fdc = (void *)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",
392 	    fdcintr, fdc);
393 	if (!fdc->sc_ih)
394 		panic("%s: Cannot claim IRQ %d", self->dv_xname, 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(struct device *parent, struct cfdata *cf, void *aux)
421 {
422 	struct fdc_softc *fdc = (void *)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(struct device *parent, struct device *self, void *aux)
476 {
477 	struct fdc_softc *fdc = (void *)parent;
478 	struct fd_softc *fd = (void *)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(struct device *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", fdc->sc_dev.dv_xname);
1032 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x01);
1033 		bus_space_write_2(iot, ioh, fdctl, type->rate);
1034 #ifdef FD_DEBUG
1035 		printf("fdcintr: %s drive %d track %d head %d sec %d nblks %d\n",
1036 			read ? "read" : "write", fd->sc_drive, fd->sc_cylin,
1037 			head, sec, nblks);
1038 #endif
1039 		if (finfo) {
1040 			/* formatting */
1041 			if (out_fdc(iot, ioh, NE7CMD_FORMAT) < 0) {
1042 				fdc->sc_errors = 4;
1043 				fdcretry(fdc);
1044 				goto loop;
1045 			}
1046 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1047 			out_fdc(iot, ioh, finfo->fd_formb_secshift);
1048 			out_fdc(iot, ioh, finfo->fd_formb_nsecs);
1049 			out_fdc(iot, ioh, finfo->fd_formb_gaplen);
1050 			out_fdc(iot, ioh, finfo->fd_formb_fillbyte);
1051 		} else {
1052 			if (read)
1053 				out_fdc(iot, ioh, NE7CMD_READ);	/* READ */
1054 			else
1055 				out_fdc(iot, ioh, NE7CMD_WRITE); /* WRITE */
1056 			out_fdc(iot, ioh, (head << 2) | fd->sc_drive);
1057 			out_fdc(iot, ioh, fd->sc_cylin); /* track */
1058 			out_fdc(iot, ioh, head);
1059 			out_fdc(iot, ioh, sec + 1);	 /* sector +1 */
1060 			out_fdc(iot, ioh, type->secsize);/* sector size */
1061 			out_fdc(iot, ioh, type->sectrac);/* sectors/track */
1062 			out_fdc(iot, ioh, type->gap1);	 /* gap1 size */
1063 			out_fdc(iot, ioh, type->datalen);/* data length */
1064 		}
1065 		fdc->sc_state = IOCOMPLETE;
1066 
1067 		disk_busy(&fd->sc_dk);
1068 
1069 		/* allow 2 seconds for operation */
1070 		callout_reset(&fdc->sc_timo_ch, 2 * hz, fdctimeout, fdc);
1071 		return 1;				/* will return later */
1072 
1073 	case SEEKWAIT:
1074 		callout_stop(&fdc->sc_timo_ch);
1075 		fdc->sc_state = SEEKCOMPLETE;
1076 		/* allow 1/50 second for heads to settle */
1077 #if 0
1078 		callout_reset(&fdc->sc_intr_ch, hz / 50, fdcpseudointr, fdc);
1079 #endif
1080 		return 1;
1081 
1082 	case SEEKCOMPLETE:
1083 		/* no data on seek */
1084 		disk_unbusy(&fd->sc_dk, 0, 0);
1085 
1086 		/* Make sure seek really happened. */
1087 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1088 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 ||
1089 		    cyl != bp->b_cylinder * fd->sc_type->step) {
1090 #ifdef FD_DEBUG
1091 			fdcstatus(&fd->sc_dev, 2, "seek failed");
1092 #endif
1093 			fdcretry(fdc);
1094 			goto loop;
1095 		}
1096 		fd->sc_cylin = bp->b_cylinder;
1097 		goto doio;
1098 
1099 	case IOTIMEDOUT:
1100 		fiq_release(&fdc->sc_fh);
1101 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1102 	case SEEKTIMEDOUT:
1103 	case RECALTIMEDOUT:
1104 	case RESETTIMEDOUT:
1105 		fdcretry(fdc);
1106 		goto loop;
1107 
1108 	case IOCOMPLETE: /* IO DONE, post-analyze */
1109 		callout_stop(&fdc->sc_timo_ch);
1110 
1111 		disk_unbusy(&fd->sc_dk, (bp->b_bcount - bp->b_resid),
1112 		    (bp->b_flags & B_READ));
1113 
1114 		if (fdcresult(fdc) != 7 || (st0 & 0xf8) != 0) {
1115 			fiq_release(&fdc->sc_fh);
1116 			IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1117 #ifdef FD_DEBUG
1118 			fdcstatus(&fd->sc_dev, 7, bp->b_flags & B_READ ?
1119 			    "read failed" : "write failed");
1120 			printf("blkno %d nblks %d\n",
1121 			    fd->sc_blkno, fd->sc_nblks);
1122 #endif
1123 			fdcretry(fdc);
1124 			goto loop;
1125 		}
1126 		fiq_release(&fdc->sc_fh);
1127 		IOMD_WRITE_BYTE(IOMD_FIQMSK, 0x00);
1128 		if (fdc->sc_errors) {
1129 #if 0
1130 			diskerr(bp, "fd", "soft error (corrected)", LOG_PRINTF,
1131 			    fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL);
1132 			printf("\n");
1133 #endif
1134 			fdc->sc_errors = 0;
1135 		}
1136 		fd->sc_blkno += fd->sc_nblks;
1137 		fd->sc_skip += fd->sc_nbytes;
1138 		fd->sc_bcount -= fd->sc_nbytes;
1139 		if (!finfo && fd->sc_bcount > 0) {
1140 			bp->b_cylinder = fd->sc_blkno / fd->sc_type->seccyl;
1141 			goto doseek;
1142 		}
1143 		fdfinish(fd, bp);
1144 		goto loop;
1145 
1146 	case DORESET:
1147 		/* try a reset, keep motor on */
1148 		fd_set_motor(fdc, 1);
1149 		delay(100);
1150 		fd_set_motor(fdc, 0);
1151 		fdc->sc_state = RESETCOMPLETE;
1152 		callout_reset(&fdc->sc_timo_ch, hz / 2, fdctimeout, fdc);
1153 		return 1;			/* will return later */
1154 
1155 	case RESETCOMPLETE:
1156 		callout_stop(&fdc->sc_timo_ch);
1157 		/* clear the controller output buffer */
1158 		for (i = 0; i < 4; i++) {
1159 			out_fdc(iot, ioh, NE7CMD_SENSEI);
1160 			(void) fdcresult(fdc);
1161 		}
1162 
1163 		/* fall through */
1164 	case DORECAL:
1165 		out_fdc(iot, ioh, NE7CMD_RECAL);	/* recalibrate function */
1166 		out_fdc(iot, ioh, fd->sc_drive);
1167 		fdc->sc_state = RECALWAIT;
1168 		callout_reset(&fdc->sc_timo_ch, 5 * hz, fdctimeout, fdc);
1169 		return 1;			/* will return later */
1170 
1171 	case RECALWAIT:
1172 		callout_stop(&fdc->sc_timo_ch);
1173 		fdc->sc_state = RECALCOMPLETE;
1174 		/* allow 1/30 second for heads to settle */
1175 #if 0
1176 		callout_reset(&fdc->sc_intr_ch, hz / 30, fdcpseudointr, fdc);
1177 #endif
1178 		return 1;			/* will return later */
1179 
1180 	case RECALCOMPLETE:
1181 		out_fdc(iot, ioh, NE7CMD_SENSEI);
1182 		if (fdcresult(fdc) != 2 || (st0 & 0xf8) != 0x20 || cyl != 0) {
1183 #ifdef FD_DEBUG
1184 			fdcstatus(&fd->sc_dev, 2, "recalibrate failed");
1185 #endif
1186 			fdcretry(fdc);
1187 			goto loop;
1188 		}
1189 		fd->sc_cylin = 0;
1190 		goto doseek;
1191 
1192 	case MOTORWAIT:
1193 		if (fd->sc_flags & FD_MOTOR_WAIT)
1194 			return 1;		/* time's not up yet */
1195 		goto doseek;
1196 
1197 	default:
1198 		fdcstatus(&fd->sc_dev, 0, "stray interrupt");
1199 		return 1;
1200 	}
1201 #ifdef DIAGNOSTIC
1202 	panic("fdcintr: impossible");
1203 #endif
1204 #undef	st0
1205 #undef	cyl
1206 }
1207 
1208 void
1209 fdcretry(struct fdc_softc *fdc)
1210 {
1211 	struct fd_softc *fd;
1212 	struct buf *bp;
1213 
1214 	fd = fdc->sc_drives.tqh_first;
1215 	bp = bufq_peek(fd->sc_q);
1216 
1217 	if (fd->sc_opts & FDOPT_NORETRY)
1218 	    goto fail;
1219 	switch (fdc->sc_errors) {
1220 	case 0:
1221 		/* try again */
1222 		fdc->sc_state = DOSEEK;
1223 		break;
1224 
1225 	case 1: case 2: case 3:
1226 		/* didn't work; try recalibrating */
1227 		fdc->sc_state = DORECAL;
1228 		break;
1229 
1230 	case 4:
1231 		/* still no go; reset the bastard */
1232 		fdc->sc_state = DORESET;
1233 		break;
1234 
1235 	default:
1236 	fail:
1237 		if ((fd->sc_opts & FDOPT_SILENT) == 0) {
1238 			diskerr(bp, "fd", "hard error", LOG_PRINTF,
1239 				fd->sc_skip / FDC_BSIZE,
1240 				(struct disklabel *)NULL);
1241 			fdcpstatus(7, fdc);
1242 		}
1243 
1244 		bp->b_error = EIO;
1245 		fdfinish(fd, bp);
1246 	}
1247 	fdc->sc_errors++;
1248 }
1249 
1250 int
1251 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
1252 {
1253 	struct fd_softc *fd = device_lookup_private(&fd_cd, FDUNIT(dev));
1254 	struct fdformat_parms *form_parms;
1255 	struct fdformat_cmd *form_cmd;
1256 	struct ne7_fd_formb *fd_formb;
1257 	struct disklabel buffer;
1258 	int error;
1259 	unsigned int scratch;
1260 	int il[FD_MAX_NSEC + 1];
1261 	register int i, j;
1262 
1263 	switch (cmd) {
1264 	case DIOCGDINFO:
1265 		memset(&buffer, 0, sizeof(buffer));
1266 
1267 		buffer.d_secpercyl = fd->sc_type->seccyl;
1268 		buffer.d_type = DTYPE_FLOPPY;
1269 		buffer.d_secsize = FDC_BSIZE;
1270 
1271 		if (readdisklabel(dev, fdstrategy, &buffer, NULL) != NULL)
1272 			return EINVAL;
1273 
1274 		*(struct disklabel *)addr = buffer;
1275 		return 0;
1276 
1277 	case DIOCWLABEL:
1278 		if ((flag & FWRITE) == 0)
1279 			return EBADF;
1280 		/* XXX do something */
1281 		return 0;
1282 
1283 	case DIOCWDINFO:
1284 		if ((flag & FWRITE) == 0)
1285 			return EBADF;
1286 
1287 		error = setdisklabel(&buffer, (struct disklabel *)addr, 0, NULL);
1288 		if (error)
1289 			return error;
1290 
1291 		error = writedisklabel(dev, fdstrategy, &buffer, NULL);
1292 		return error;
1293 
1294 	case FDIOCGETFORMAT:
1295 		form_parms = (struct fdformat_parms *)addr;
1296 		form_parms->fdformat_version = FDFORMAT_VERSION;
1297 		form_parms->nbps = 128 * (1 << fd->sc_type->secsize);
1298 		form_parms->ncyl = fd->sc_type->cyls;
1299 		form_parms->nspt = fd->sc_type->sectrac;
1300 		form_parms->ntrk = fd->sc_type->heads;
1301 		form_parms->stepspercyl = fd->sc_type->step;
1302 		form_parms->gaplen = fd->sc_type->gap2;
1303 		form_parms->fillbyte = fd->sc_type->fillbyte;
1304 		form_parms->interleave = fd->sc_type->interleave;
1305 		switch (fd->sc_type->rate) {
1306 		case FDC_500KBPS:
1307 			form_parms->xfer_rate = 500 * 1024;
1308 			break;
1309 		case FDC_300KBPS:
1310 			form_parms->xfer_rate = 300 * 1024;
1311 			break;
1312 		case FDC_250KBPS:
1313 			form_parms->xfer_rate = 250 * 1024;
1314 			break;
1315 		default:
1316 			return EINVAL;
1317 		}
1318 		return 0;
1319 
1320 	case FDIOCSETFORMAT:
1321 		if((flag & FWRITE) == 0)
1322 			return EBADF;	/* must be opened for writing */
1323 		form_parms = (struct fdformat_parms *)addr;
1324 		if (form_parms->fdformat_version != FDFORMAT_VERSION)
1325 			return EINVAL;	/* wrong version of formatting prog */
1326 
1327 		scratch = form_parms->nbps >> 7;
1328 		if ((form_parms->nbps & 0x7f) || ffs(scratch) == 0 ||
1329 		    scratch & ~(1 << (ffs(scratch)-1)))
1330 			/* not a power-of-two multiple of 128 */
1331 			return EINVAL;
1332 
1333 		switch (form_parms->xfer_rate) {
1334 		case 500 * 1024:
1335 			fd->sc_type->rate = FDC_500KBPS;
1336 			break;
1337 		case 300 * 1024:
1338 			fd->sc_type->rate = FDC_300KBPS;
1339 			break;
1340 		case 250 * 1024:
1341 			fd->sc_type->rate = FDC_250KBPS;
1342 			break;
1343 		default:
1344 			return EINVAL;
1345 		}
1346 
1347 		if (form_parms->nspt > FD_MAX_NSEC ||
1348 		    form_parms->fillbyte > 0xff ||
1349 		    form_parms->interleave > 0xff)
1350 			return EINVAL;
1351 		fd->sc_type->sectrac = form_parms->nspt;
1352 		if (form_parms->ntrk != 2 && form_parms->ntrk != 1)
1353 			return EINVAL;
1354 		fd->sc_type->heads = form_parms->ntrk;
1355 		fd->sc_type->seccyl = form_parms->nspt * form_parms->ntrk;
1356 		fd->sc_type->secsize = ffs(scratch)-1;
1357 		fd->sc_type->gap2 = form_parms->gaplen;
1358 		fd->sc_type->cyls = form_parms->ncyl;
1359 		fd->sc_type->size = fd->sc_type->seccyl * form_parms->ncyl *
1360 			form_parms->nbps / DEV_BSIZE;
1361 		fd->sc_type->step = form_parms->stepspercyl;
1362 		fd->sc_type->fillbyte = form_parms->fillbyte;
1363 		fd->sc_type->interleave = form_parms->interleave;
1364 		return 0;
1365 
1366 	case FDIOCFORMAT_TRACK:
1367 		if((flag & FWRITE) == 0)
1368 			return EBADF;	/* must be opened for writing */
1369 		form_cmd = (struct fdformat_cmd *)addr;
1370 		if (form_cmd->formatcmd_version != FDFORMAT_VERSION)
1371 			return EINVAL;	/* wrong version of formatting prog */
1372 
1373 		if (form_cmd->head >= fd->sc_type->heads ||
1374 		    form_cmd->cylinder >= fd->sc_type->cyls) {
1375 			return EINVAL;
1376 		}
1377 
1378 		fd_formb = malloc(sizeof(struct ne7_fd_formb),
1379 		    M_TEMP, M_NOWAIT);
1380 		if(fd_formb == 0)
1381 			return ENOMEM;
1382 
1383 
1384 		fd_formb->head = form_cmd->head;
1385 		fd_formb->cyl = form_cmd->cylinder;
1386 		fd_formb->transfer_rate = fd->sc_type->rate;
1387 		fd_formb->fd_formb_secshift = fd->sc_type->secsize;
1388 		fd_formb->fd_formb_nsecs = fd->sc_type->sectrac;
1389 		fd_formb->fd_formb_gaplen = fd->sc_type->gap2;
1390 		fd_formb->fd_formb_fillbyte = fd->sc_type->fillbyte;
1391 
1392 		memset(il, 0, sizeof il);
1393 		for (j = 0, i = 1; i <= fd_formb->fd_formb_nsecs; i++) {
1394 			while (il[(j%fd_formb->fd_formb_nsecs)+1])
1395 				j++;
1396 			il[(j%fd_formb->fd_formb_nsecs)+1] = i;
1397 			j += fd->sc_type->interleave;
1398 		}
1399 		for (i = 0; i < fd_formb->fd_formb_nsecs; i++) {
1400 			fd_formb->fd_formb_cylno(i) = form_cmd->cylinder;
1401 			fd_formb->fd_formb_headno(i) = form_cmd->head;
1402 			fd_formb->fd_formb_secno(i) = il[i+1];
1403 			fd_formb->fd_formb_secsize(i) = fd->sc_type->secsize;
1404 		}
1405 
1406 		error = fdformat(dev, fd_formb, l);
1407 		free(fd_formb, M_TEMP);
1408 		return error;
1409 
1410 	case FDIOCGETOPTS:		/* get drive options */
1411 		*(int *)addr = fd->sc_opts;
1412 		return 0;
1413 
1414 	case FDIOCSETOPTS:		/* set drive options */
1415 		fd->sc_opts = *(int *)addr;
1416 		return 0;
1417 
1418 	default:
1419 		return ENOTTY;
1420 	}
1421 
1422 #ifdef DIAGNOSTIC
1423 	panic("fdioctl: impossible");
1424 #endif
1425 }
1426 
1427 int
1428 fdformat(dev_t dev, struct ne7_fd_formb *finfo, struct lwp *l)
1429 {
1430 	int rv = 0;
1431 	struct fd_softc *fd = device_lookup_private(&fd_cd,FDUNIT(dev));
1432 	struct fd_type *type = fd->sc_type;
1433 	struct buf *bp;
1434 
1435 	/* set up a buffer header for fdstrategy() */
1436 	bp = getiobuf(NULL, false);
1437 	if(bp == 0)
1438 		return ENOBUFS;
1439 	bp->b_flags = B_PHYS | B_FORMAT;
1440 	bp->b_cflags |= BC_BUSY;
1441 	bp->b_proc = l->l_proc;
1442 	bp->b_dev = dev;
1443 
1444 	/*
1445 	 * calculate a fake blkno, so fdstrategy() would initiate a
1446 	 * seek to the requested cylinder
1447 	 */
1448 	bp->b_blkno = (finfo->cyl * (type->sectrac * type->heads)
1449 		       + finfo->head * type->sectrac) * FDC_BSIZE / DEV_BSIZE;
1450 
1451 	bp->b_bcount = sizeof(struct fd_idfield_data) * finfo->fd_formb_nsecs;
1452 	bp->b_data = (void *)finfo;
1453 
1454 #ifdef DEBUG
1455 	printf("fdformat: blkno %llx count %x\n",
1456 	    (unsigned long long)bp->b_blkno, bp->b_bcount);
1457 #endif
1458 
1459 	/* now do the format */
1460 	fdstrategy(bp);
1461 
1462 	/* ...and wait for it to complete */
1463 	/* XXX very dodgy */
1464 	mutex_enter(bp->b_objlock);
1465 	while (!(bp->b_oflags & BO_DONE)) {
1466 		rv = cv_timedwait(&bp->b_done, bp->b_objlock, 20 * hz);
1467 		if (rv == EWOULDBLOCK)
1468 			break;
1469 	}
1470 	mutex_exit(bp->b_objlock);
1471 
1472 	if (rv == EWOULDBLOCK) {
1473 		/* timed out */
1474 		rv = EIO;
1475 		biodone(bp);
1476 	} else if (bp->b_error != 0)
1477 		rv = bp->b_error;
1478 	putiobuf(bp);
1479 	return rv;
1480 }
1481 
1482 #include <dev/md.h>
1483 
1484 int load_memory_disc_from_floppy(struct md_conf *md, dev_t dev);
1485 
1486 int
1487 load_memory_disc_from_floppy(struct md_conf *md, dev_t dev)
1488 {
1489 	struct buf *bp;
1490 	int loop;
1491 	int s;
1492 	int type;
1493 	int floppysize;
1494 
1495 	if (bdevsw_lookup(dev) != &fd_bdevsw)
1496 		return(EINVAL);
1497 
1498 	if (md->md_type == MD_UNCONFIGURED || md->md_addr == 0)
1499 		return(EBUSY);
1500 
1501 	type = FDTYPE(dev) - 1;
1502 	if (type < 0) type = 0;
1503 	floppysize = fd_types[type].size << (fd_types[type].secsize + 7);
1504 
1505 	if (md->md_size < floppysize) {
1506 		printf("Memory disc is not big enough for floppy image\n");
1507 		return(EINVAL);
1508 	}
1509 
1510 /* We have the memory disk ! */
1511 
1512 	printf("Loading memory disc : %4dK ", 0);
1513 
1514 /* obtain a buffer */
1515 
1516 	bp = geteblk(fd_types[type].sectrac * DEV_BSIZE);
1517 
1518 /* request no partition relocation by driver on I/O operations */
1519 
1520 	bp->b_dev = dev;
1521 
1522 	s = splbio();
1523 
1524 	if (fdopen(bp->b_dev, 0, 0, curlwp) != 0) {
1525 		brelse(bp, 0);
1526 		printf("Cannot open floppy device\n");
1527 			return(EINVAL);
1528 	}
1529 
1530 	for (loop = 0;
1531 	    loop < (floppysize / DEV_BSIZE / fd_types[type].sectrac);
1532 	    ++loop) {
1533 		printf("\x08\x08\x08\x08\x08\x08%4dK ",
1534 		    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1535 		bp->b_blkno = loop * fd_types[type].sectrac;
1536 		bp->b_bcount = fd_types[type].sectrac * DEV_BSIZE;
1537 		bp->b_flags |= B_READ;
1538 		bp->b_error = 0;
1539 		bp->b_resid = 0;
1540 		fdstrategy(bp);
1541 
1542 		if (biowait(bp))
1543 			panic("Cannot load floppy image");
1544 
1545 		memcpy((char *)md->md_addr + loop * fd_types[type].sectrac
1546 		    * DEV_BSIZE, (void *)bp->b_data,
1547 		    fd_types[type].sectrac * DEV_BSIZE);
1548 	}
1549 	printf("\x08\x08\x08\x08\x08\x08%4dK done\n",
1550 	    loop * fd_types[type].sectrac * DEV_BSIZE / 1024);
1551 
1552 	fdclose(bp->b_dev, 0, 0, curlwp);
1553 
1554 	brelse(bp, 0);
1555 
1556 	splx(s);
1557 	return(0);
1558 }
1559